<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://metanokid.github.io/coding-scars/feed.xml" rel="self" type="application/atom+xml" /><link href="https://metanokid.github.io/coding-scars/" rel="alternate" type="text/html" /><updated>2022-03-11T23:29:57+00:00</updated><id>https://metanokid.github.io/coding-scars/feed.xml</id><title type="html">codingScars</title><subtitle>Programming blog</subtitle><entry><title type="html">Getting data from C++ Build Insights SDK</title><link href="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-4/" rel="alternate" type="text/html" title="Getting data from C++ Build Insights SDK" /><published>2020-05-01T00:00:00+00:00</published><updated>2020-05-01T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-4</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-4/">&lt;p&gt;Welcome back to the series!&lt;/p&gt;

&lt;p&gt;In the previous posts we’ve explored ways to find how long a C++ build takes, installed some tools and found a way to create flame graphs out of MSBuild’s execution.&lt;/p&gt;

&lt;p&gt;Join me this time as we explore a brand new SDK that lets us get better data in an easier manner!&lt;/p&gt;

&lt;h1 id=&quot;c-build-insights-sdk&quot;&gt;C++ Build Insights SDK&lt;/h1&gt;

&lt;p&gt;Last november &lt;a href=&quot;https://twitter.com/KevinCadieuxMS&quot;&gt;@KevinCadieuxMS&lt;/a&gt; shared a &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/introducing-c-build-insights/&quot; target=&quot;_blank&quot;&gt;post over at Microsoft’s C++ Team Blog&lt;/a&gt; announcing a brand new tool called &lt;strong&gt;vcperf&lt;/strong&gt; to get extensive data out of a C++ compilation. It required getting Visual Studio 16.4 as vcperf is part of the installation.&lt;/p&gt;

&lt;p&gt;Last march they went further:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They released the &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/analyze-your-builds-programmatically-with-the-c-build-insights-sdk/&quot; target=&quot;_blank&quot;&gt;C++ Build Insights SDK&lt;/a&gt; so we can use it ourselves.&lt;/li&gt;
  &lt;li&gt;They &lt;a href=&quot;https://github.com/microsoft/vcperf&quot; target=&quot;_blank&quot;&gt;open sourced vcperf&lt;/a&gt;, which serves as an example tool using the SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So first of all, let me thank Kevin and all of the team for providing us with these extra tools. They’re highly appreciated and useful!&lt;/p&gt;

&lt;p&gt;And there I was, finishing the initial release of my &lt;a href=&quot;https://github.com/MetanoKid/msbuild-flame-graph&quot; target=&quot;_blank&quot;&gt;MSBuildFlameGraph&lt;/a&gt; tool as they released this SDK that made my tool almost deprecated! So, I set myself on a quest to explore it and this is what I found.&lt;/p&gt;

&lt;p&gt;Disclaimer: this post is based on the 1.0.0 version of the C++ Build Insights SDK. It’s expected it evolves over time and some of this info can become stale!&lt;/p&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;Instead of writing an incomplete and outdated list of steps to get it working, let me point you to the &lt;a href=&quot;https://docs.microsoft.com/cpp/build-insights/reference/sdk/overview&quot; target=&quot;_blank&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There, you’ll get info on how to collect a trace using vcperf or how the SDK is structured. We’ll be taking a look at some of its points now.&lt;/p&gt;

&lt;h2 id=&quot;activities-and-events&quot;&gt;Activities and events&lt;/h2&gt;

&lt;p&gt;Put simply, the basic piece of information the SDK reports is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Event&lt;/code&gt;. They have an id, a timestamp, a name and the &lt;em&gt;real&lt;/em&gt; process/thread/processor they were emitted from. They can also have extra data depending on which event type they are.&lt;/p&gt;

&lt;p&gt;When an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Event&lt;/code&gt; is instant they call them &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleEvent&lt;/code&gt;, while it’s called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Activity&lt;/code&gt; if it takes time to complete (and also provides the timestamp when it finished).&lt;/p&gt;

&lt;p&gt;You can check the full list of activities and events at the &lt;a href=&quot;https://docs.microsoft.com/cpp/build-insights/reference/sdk/event-table&quot; target=&quot;_blank&quot;&gt;official docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;hierarchies&quot;&gt;Hierarchies&lt;/h3&gt;

&lt;p&gt;Because activities have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Duration&lt;/code&gt; and take some time to complete, there can be other activities and events that execute within them. This way, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Activity&lt;/code&gt; can have both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Activity&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleEvent&lt;/code&gt; children. On the other hand, every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleEvent&lt;/code&gt; is instant and can’t have any children.&lt;/p&gt;

&lt;p&gt;After reading the event table and not being able to make a mental map myself, I decided to build a directed graph to visualize them.&lt;/p&gt;

&lt;p&gt;These are the parent-child relationships for activities (yellow-bordered are top-level ones):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/activities.png&quot; alt=&quot;C++ Build Insights SDK Activities&quot; title=&quot;Activities&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;These are the parent-child relationships with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleEvent&lt;/code&gt; included (gray-shaded):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/activities-events.png&quot; alt=&quot;C++ Build Insights SDK Activities and Simple Events&quot; title=&quot;Activities and Simple Events&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we were to check the event table from the docs, we’d see each one of the event types we’ve seen matches a class: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FRONT_END_PASS&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FrontEndPass&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WHOLE_PROGRAM_OPTIMIZATION&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WholeProgramOptimization&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;Let’s keep this graph in mind as we continue exploring.&lt;/p&gt;

&lt;h2 id=&quot;exploring-the-sdk-via-code&quot;&gt;Exploring the SDK via code&lt;/h2&gt;

&lt;p&gt;When you want to analyze a build you’ll usually perform these steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vcperf /start SomeTraceName&lt;/code&gt; from an elevated command-line prompt.&lt;/li&gt;
  &lt;li&gt;Build your project (from Visual Studio or command-line, no matter which).&lt;/li&gt;
  &lt;li&gt;Execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vcperf /stopnoanalyze SomeTraceName OutputFile.etl&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Analyze &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OutputFile.etl&lt;/code&gt; with your tool (using the SDK).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that, although you can record traces yourself with the SDK, I’ll keep using &lt;strong&gt;vcperf&lt;/strong&gt; for that.&lt;/p&gt;

&lt;p&gt;This is the basic code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;CppBuildInsights.hpp&amp;gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// shorthand namespace version for convenience&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Microsoft&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cpp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BuildInsights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SampleAnalyzer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IAnalyzer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SampleAnalyzer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MakeStaticAnalyzerGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;analyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analysisPasses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RESULT_CODE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Analyze&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;OutputFile.etl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;analysisPasses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RESULT_CODE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RESULT_CODE_SUCCESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXIT_SUCCESS&lt;/span&gt;
                                                           &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s all of the setup you need to do to get working! Now we need to know how to get useful data from the trace.&lt;/p&gt;

&lt;p&gt;Please note I’ll be using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CppBI&lt;/code&gt; as an alias to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft::Cpp::BuildInsights&lt;/code&gt; so code sections require as little horizontal scrolling as possible.&lt;/p&gt;

&lt;h3 id=&quot;ianalyzer&quot;&gt;IAnalyzer&lt;/h3&gt;

&lt;p&gt;There are three main member functions you need to know from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IAnalyzer&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnStartActivity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EventStack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnStopActivity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EventStack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnSimpleEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EventStack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The SDK calls these whenever an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Event&lt;/code&gt; is read from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.etl&lt;/code&gt; file. Which one depends on the kind of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Event&lt;/code&gt; that was reported (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Activity&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SimpleEvent&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;So what’s that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventStack&lt;/code&gt;? Whenever an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Event&lt;/code&gt; is emitted we also get its context via this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventStack&lt;/code&gt;. Let’s say we get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnStopActivity&lt;/code&gt; called. An example of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventStack&lt;/code&gt; could be:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Function         &amp;lt;- top of stack
Thread
CodeGeneration
C2DLL
BackEndPass
Compiler
-----------------&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Or say we get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnSimpleEvent&lt;/code&gt; called:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;SymbolName       &amp;lt;- top of stack
C1DLL
FrontEndPass
Compiler
-----------------&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But how do we retrieve different events within the stack?&lt;/p&gt;

&lt;h3 id=&quot;matchers&quot;&gt;Matchers&lt;/h3&gt;

&lt;p&gt;Let’s say we want to know all of the command-line options within our trace. We explore the official docs and find there’s a &lt;a href=&quot;https://docs.microsoft.com/cpp/build-insights/reference/sdk/cpp-event-data-types/command-line&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CommandLine&lt;/code&gt;&lt;/a&gt; event type. We’d add this method to our class:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnCommandLineEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleEvents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommandLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The SDK has a very clever way of helping you get the events you’re interested in within a hierarchy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SampleAnalyzer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IAnalyzer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnSimpleEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EventStack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MatchEventStackInMemberFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SampleAnalyzer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnCommandLineEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONTINUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MatchEventStackInMemberFunction&lt;/code&gt; call there makes magic and filters those stacks which contain the event types in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnCommandLineEvent&lt;/code&gt; signature.&lt;/p&gt;

&lt;p&gt;We now know all of the command-line options within the trace, but they’re all mixed up. Remember how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compiler&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Linker&lt;/code&gt; activities were parents of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CommandLine&lt;/code&gt; events? Wouldn’t it be awesome to tell them apart?&lt;/p&gt;

&lt;p&gt;Let’s create these two methods this time:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnCompilerCommandLineEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleEvents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommandLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Compiler: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnLinkerCommandLineEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SimpleEvents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommandLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Linker: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;See how the signature now takes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CommandLine&lt;/code&gt; preceded by either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compiler&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Linker&lt;/code&gt;?. Now let’s update our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnSimpleEvent&lt;/code&gt; method to use them both:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnSimpleEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EventStack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MatchEventStackInMemberFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                         &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                         &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SampleAnalyzer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnCompilerCommandLineEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MatchEventStackInMemberFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                         &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                         &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SampleAnalyzer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnLinkerCommandLineEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONTINUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Magically, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MatchEventStackInMemberFunction&lt;/code&gt; will match those stacks that have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compiler&lt;/code&gt; activity and then a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CommandLine&lt;/code&gt; event apart from those with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Linker&lt;/code&gt; activity and then a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CommandLine&lt;/code&gt; event!&lt;/p&gt;

&lt;p&gt;You can get more info on matchers and examples on the &lt;a href=&quot;https://docs.microsoft.com/cpp/build-insights/reference/sdk/functions/match-event-stack-in-member-function&quot; target=&quot;_blank&quot;&gt;official docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;getting-more-useful-data-with-the-sdk&quot;&gt;Getting more useful data with the SDK&lt;/h2&gt;

&lt;p&gt;Now we know how to deal with the SDK, let’s try to get some data out of our build, shall we?&lt;/p&gt;

&lt;p&gt;In this case we’ll be using a default Unreal Engine project. Oh, and because it’s the compiler and linker the ones emitting the events we can get data from projects not supported in &lt;a href=&quot;https://github.com/MetanoKid/msbuild-flame-graph&quot; target=&quot;_blank&quot;&gt;MSBuildFlameGraph&lt;/a&gt;!&lt;/p&gt;

&lt;h3 id=&quot;collecting-a-trace&quot;&gt;Collecting a trace&lt;/h3&gt;

&lt;p&gt;Before we can start, we need a trace to work with! These were my steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Installed Visual Studio 15.9.22 (Visual Studio 2017).&lt;/li&gt;
  &lt;li&gt;Cloned &lt;a href=&quot;https://github.com/microsoft/vcperf&quot; target=&quot;_blank&quot;&gt;vcperf from GitHub&lt;/a&gt; and built it.&lt;/li&gt;
  &lt;li&gt;Installed Unreal Engine 4.24.3, launched it and created the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;First Person Shooter&lt;/code&gt; project with C++ code.&lt;/li&gt;
  &lt;li&gt;Launched an elevated command prompt and navigated to the previous vcperf output directory.&lt;/li&gt;
  &lt;li&gt;Executed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vcperf /start UE4Project&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;In Visual Studio 2017, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rebuild&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Development|Win64&lt;/code&gt; our Unreal Engine solution.&lt;/li&gt;
  &lt;li&gt;Executed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vcperf /stopnoanalyze UE4Project UE4Project.etl&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we’ve got an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UE4Project.etl&lt;/code&gt; trace to analyze!&lt;/p&gt;

&lt;p&gt;Oh, the computer I ran it on is a 8-year-old i5 laptop with no SSD and low RAM, so expect slow times here!&lt;/p&gt;

&lt;h3 id=&quot;listing-slowest-files-to-compile&quot;&gt;Listing slowest files to compile&lt;/h3&gt;

&lt;p&gt;Before we get some code, we should go back to the directed graph we built before:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/activities.png&quot; alt=&quot;C++ Build Insights SDK Activities&quot; title=&quot;Activities&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See how both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FRONT_END_PASS&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BACK_END_PASS&lt;/code&gt; live within the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COMPILER&lt;/code&gt; activity? After a &lt;a href=&quot;https://docs.microsoft.com/cpp/build-insights/reference/sdk/cpp-event-data-types/compiler-pass&quot; target=&quot;_blank&quot;&gt;quick check with the official docs&lt;/a&gt; we can see both classes inherit from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompilerPass&lt;/code&gt;. And that class has two interesting members:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InputSourcePath&lt;/code&gt;: path to the source file that gets compiled.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OutputObjectPath&lt;/code&gt;: path to the compiled output file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, because they inherit from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Activity&lt;/code&gt; we can check the time it took from start to stop via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Duration&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nice! So we’ve got all the info we need. Now let’s write some code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FileCompilationsAnalyzer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IAnalyzer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;FileCompilationsAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_fileCompilationsData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileCompilationsAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnStopActivity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EventStack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MatchEventStackInMemberFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                       &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                       &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileCompilationsAnalyzer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnFrontEndPassCompleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
                     &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MatchEventStackInMemberFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                       &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                       &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileCompilationsAnalyzer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnBackEndPassCompleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONTINUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;private:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FileCompilationData&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nanoseconds&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frontEndDuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nanoseconds&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backEndDuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unordered_map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileCompilationData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_fileCompilationsData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnFrontEndPassCompleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FrontEndPass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frontEndPass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_fileCompilationsData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;try_emplace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frontEndPass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InputSourcePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                                                     &lt;span class=&quot;n&quot;&gt;FileCompilationData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frontEndDuration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frontEndPass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnBackEndPassCompleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BackEndPass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backEndPass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_fileCompilationsData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;try_emplace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backEndPass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InputSourcePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                                                     &lt;span class=&quot;n&quot;&gt;FileCompilationData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backEndDuration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backEndPass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And that’s all we need! We can now run our code, sort the data we’ve collected and dump it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectCharacter.cpp
  Total time: 82.724s (front-end: 81.086s, back-end: 1.638s)
path\DefaultFPSCppProjectEditor\Development\Engine\SharedPCH.Engine.ShadowErrors.h
  Total time: 81.302s (front-end: 74.104s, back-end: 7.198s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectGameMode.cpp
  Total time: 75.965s (front-end: 74.640s, back-end: 1.325s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectProjectile.cpp
  Total time: 75.914s (front-end: 74.615s, back-end: 1.300s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectHUD.cpp
  Total time: 75.535s (front-end: 74.570s, back-end: 0.964s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectCharacter.gen.cpp
  Total time: 3.071s  (front-end: 2.131s,  back-end: 0.940s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectGameMode.gen.cpp
  Total time: 3.024s  (front-end: 1.875s,  back-end: 1.149s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectHUD.gen.cpp
  Total time: 2.671s  (front-end: 2.030s,  back-end: 0.641s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProjectProjectile.gen.cpp
  Total time: 2.358s  (front-end: 1.654s,  back-end: 0.704s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProject.init.gen.cpp
  Total time: 2.253s  (front-end: 1.424s,  back-end: 0.829s)
path\UE4Editor\Development\DefaultFPSCppProject\DefaultFPSCppProject.cpp
  Total time: 1.212s  (front-end: 0.824s,  back-end: 0.388s)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s it, now we know which files take longer to compile! And it looks like front-end times are way larger than back-end ones!&lt;/p&gt;

&lt;p&gt;Important note: it looks like projects compiled with Visual Studio 2017 (tested with version 15.9.22) report their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InputSourcePath&lt;/code&gt; as null (but their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OutputObjectPath&lt;/code&gt; is correct). This seems to work without a problem if you compile your project with Visual Studio 2019 (tested with version 16.5.2). For the sake of this section I had ommited this issue until now.&lt;/p&gt;

&lt;h3 id=&quot;listing-slowest-files-to-get-included&quot;&gt;Listing slowest files to get included&lt;/h3&gt;

&lt;p&gt;This time we want to query the SDK for included files. Remember: file inclusion gets performed by the front-end. After a bit of searching we come up with &lt;a href=&quot;https://docs.microsoft.com/cpp/build-insights/reference/sdk/cpp-event-data-types/front-end-file&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FrontEndFile&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Activity&lt;/code&gt; is recursive, as a file can include some file that in turn includes some other file. However, we’re only interested in files that get included &lt;em&gt;from other file&lt;/em&gt;. That means we want to capture a stack with two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FrontEndFile&lt;/code&gt; events!&lt;/p&gt;

&lt;p&gt;Let’s see some code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FileInclusionsAnalyzer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IAnalyzer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;FileInclusionsAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_fileInclusionTimes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileInclusionsAnalyzer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnStopActivity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EventStack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MatchEventStackInMemberFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eventStack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileInclusionsAnalyzer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnFileParsed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalysisControl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CONTINUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;private:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nanoseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TTimeElapsedPerOccurrence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unordered_map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TTimeElapsedPerOccurrence&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TTimeElapsedPerInclusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;TTimeElapsedPerInclusion&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_fileInclusionTimes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnFileParsed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FrontEndFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fromFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CppBI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Activities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FrontEndFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;includedFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_fileInclusionTimes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;try_emplace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;includedFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                                                   &lt;span class=&quot;n&quot;&gt;TTimeElapsedPerOccurrence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;includedFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And that’s it! Now we have a list of the times it took to include each file (one file can be included from several files!). Why don’t we sort all inclusions by total inclusion time and dump the first ones?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;project\path\source\defaultfpscppproject\defaultfpscppprojectcharacter.h
  Total inclusion time: 49.854s (included 3 times)
ue_4.24\engine\source\runtime\engine\classes\gameframework\character.h
  Total inclusion time: 48.960s (included 3 times)
project\path\source\defaultfpscppproject\defaultfpscppprojectgamemode.h
  Total inclusion time: 43.096s (included 2 times)
ue_4.24\engine\source\runtime\engine\classes\gameframework\gamemodebase.h
  Total inclusion time: 42.405s (included 2 times)
ue_4.24\engine\source\runtime\engine\classes\gameframework\rootmotionsource.h
  Total inclusion time: 40.776s (included 3 times)
project\path\intermediate\[...]\engine\sharedpch.engine.shadowerrors.h
  Total inclusion time: 40.732s (included 1 times)
ue_4.24\engine\source\runtime\engine\public\enginesharedpch.h
  Total inclusion time: 40.729s (included 1 times)
project\path\source\defaultfpscppproject\defaultfpscppprojecthud.h
  Total inclusion time: 39.853s (included 3 times)
ue_4.24\engine\source\runtime\engine\classes\gameframework\hud.h
  Total inclusion time: 39.142s (included 3 times)
ue_4.24\engine\source\runtime\engine\classes\engine\serverstatreplicator.h
  Total inclusion time: 28.980s (included 2 times)
[...]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Easy!&lt;/p&gt;

&lt;h3 id=&quot;generate-a-directed-graph-for-file-inclusions&quot;&gt;Generate a directed graph for file inclusions&lt;/h3&gt;

&lt;p&gt;With the previous analyzer we could also get the inclusion relationships between files, can’t we? This time I won’t add any code, but a couple of screenshots of the resulting inclusion graph (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.dgml&lt;/code&gt; format):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/ue4project-inclusion-graph.png&quot; alt=&quot;Default Unreal Engine 4 FPS project inclusion graph&quot; title=&quot;Default Unreal Engine 4 FPS project inclusion graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yeah, no joke. That’s what I can see in a laptop resolution without zooming in! Let’s zoom a bit into something, shall we?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/ue4project-inclusion-graph-slowest-file-to-include.png&quot; alt=&quot;Default Unreal Engine 4 FPS project inclusion graph, only slowest file to include and related&quot; title=&quot;Default Unreal Engine 4 FPS project inclusion graph, only slowest file to include and related&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve zoomed into the file we saw is the slowest to compile. It also shows which files include it and which files get included by it. To cut the graph down I installed Visual Studio’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DgmlPowerTools&lt;/code&gt; extension, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl+F&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DefaultFPSCppProjectCharacter.h&lt;/code&gt; to select the node and clicked the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Butterfly&lt;/code&gt; option.&lt;/p&gt;

&lt;h2 id=&quot;generate-a-flame-graph&quot;&gt;Generate a flame graph&lt;/h2&gt;

&lt;p&gt;There are other useful metrics to get, like how long do functions take to compile (careful, SDK reports their names mangled!), how many files get included on each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.h&lt;/code&gt; file or &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/finding-build-bottlenecks-with-cpp-build-insights/&quot; target=&quot;_blank&quot;&gt;whether files compile in parallel at all&lt;/a&gt;. I’m sure you can come up with more! But this time, we want to visualize the build.&lt;/p&gt;

&lt;p&gt;First of all, we have to go back to vcperf. When it analyzes a trace, it generates extra data to view within Windows Performance Analyzer (WPA). However, although it gives very useful insights, I find myself a bit clumsy while exploring it. Please refer to &lt;a href=&quot;https://github.com/microsoft/vcperf&quot; target=&quot;_blank&quot;&gt;vcperf on GitHub&lt;/a&gt; to get a glimpse of how it looks.&lt;/p&gt;

&lt;p&gt;Over a year ago, &lt;a href=&quot;https://twitter.com/aras_p&quot;&gt;@aras_p&lt;/a&gt; wrote this &lt;a href=&quot;https://aras-p.info/blog/2019/01/16/time-trace-timeline-flame-chart-profiler-for-Clang/&quot;&gt;blog post&lt;/a&gt; on how to get a flame graph out of Clang’s compilations. So, after all this time, why don’t we try to get this kind of trace from MSVC?&lt;/p&gt;

&lt;p&gt;We’d have to create a new analyzer to feed into the SDK that records all hierarchies and sets useful names for each entry in the graph. This means taking file paths from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FrontEndFile&lt;/code&gt;, function names from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function&lt;/code&gt; and the like. Be careful, though, as reported events live in the stack and will get out of scope if you want to keep pointers to them!&lt;/p&gt;

&lt;p&gt;Let’s take a look at the raw result!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/ue4project-flame-graph-raw-process-thread.png&quot; alt=&quot;Default Unreal Engine 4 FPS project flame graph&quot; title=&quot;Default Unreal Engine 4 FPS project flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well, not specially readable either, isn’t it? To the left of the image we can see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProcessId&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThreadId&lt;/code&gt; as reported by the SDK. And if we want to know what’s going on we have to scroll back and forth, trying to know which entry matches which parent. Or, what’s compiling in parallel? Found myself feeling as clumsy as when using WPA.&lt;/p&gt;

&lt;p&gt;But, can we do any better?&lt;/p&gt;

&lt;h3 id=&quot;packing-parent-children-together&quot;&gt;Packing parent-children together&lt;/h3&gt;

&lt;p&gt;Let’s post-process the data and try to keep child entries as close as possible to their parents, being careful to leave the necessary space to fit them when we have entries running in parallel.&lt;/p&gt;

&lt;p&gt;With a bit of work, we get this version:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/ue4project-flame-graph-recalculated-process-thread.png&quot; alt=&quot;Default Unreal Engine 4 FPS project flame graph, with recalculated ProcessId and ThreadId&quot; title=&quot;Default Unreal Engine 4 FPS project flame graph, with recalculated ProcessId and ThreadId&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProcessId&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThreadId&lt;/code&gt; aren’t &lt;em&gt;the real ones&lt;/em&gt; anymore. However, they approach to a more logical distribution of what’s running where! Definitely easier to read for me!&lt;/p&gt;

&lt;p&gt;Let’s zoom into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DefaultFPSCppProjectGameMode.gen.cpp&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/ue4project-flame-graph-game-mode.png&quot; alt=&quot;Default Unreal Engine 4 FPS project game mode's flame graph&quot; title=&quot;Default Unreal Engine 4 FPS project game mode's flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What can we see here? As part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C1DLL&lt;/code&gt; activity we see that this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.cpp&lt;/code&gt; file includes three other files. We also see that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodeGeneration&lt;/code&gt; activity has all of the functions that get generated (they get generated in parallel, up to 4 because my computer has 4 logical cores).&lt;/p&gt;

&lt;p&gt;But we can see something else: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compiler&lt;/code&gt; activity &lt;em&gt;only&lt;/em&gt; spans the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FrontEndPass&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackEndPass&lt;/code&gt; of this file. And, if we go back to the full trace, all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compiler&lt;/code&gt; activities only deal with one file. This maps to having a lot of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; MSBuild tasks! Does this mean we aren’t compiling in parallel?&lt;/p&gt;

&lt;p&gt;Well, apparently we are compiling in parallel we check the full trace. It looks UnrealHeaderTool is spawning as many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cl.exe&lt;/code&gt; in parallel as files we want to compile, instead of letting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cl.exe&lt;/code&gt; do the parallelization itself?&lt;/p&gt;

&lt;h3 id=&quot;getting-template-instantiation-data&quot;&gt;Getting template instantiation data&lt;/h3&gt;

&lt;p&gt;The last cool thing we’ll see requires using the &lt;a href=&quot;https://github.com/microsoft/vcperf&quot; target=&quot;_blank&quot;&gt;open source version of vcperf&lt;/a&gt; as well as compiling with Visual Studio 16.4 (Visual Studio 2019). This version of vcperf reports some extra events than the one shipping with Visual Studio 2019.&lt;/p&gt;

&lt;p&gt;This time, we’ll use &lt;a href=&quot;https://twitter.com/BruceDawson0xB&quot; target=&quot;_blank&quot;&gt;@BruceDawson0xB&lt;/a&gt;’s project from &lt;a href=&quot;https://randomascii.wordpress.com/2014/03/22/make-vc-compiles-fast-through-parallel-compilation/&quot; target=&quot;_blank&quot;&gt;this blog post&lt;/a&gt;, but updated to Visual Studio 2019. Let’s take a look:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/template-instantiations.png&quot; alt=&quot;Template instantiations&quot; title=&quot;Template instantiations&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Bruce wanted to make compilations slow and calculated Fibonacci in templates (with some tricks to prevent the compiler from reusing template instantiations). And this is the result!&lt;/p&gt;

&lt;p&gt;Of course, these template instantiations can be seen in other projects! This time we’ll build the tool I’ve used for this post in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Release|x64&lt;/code&gt; and zoom into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.cpp&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/cpp-build-analyzer-template-instantiations.png&quot; alt=&quot;CppBuildAnalyzer's Main.cpp with template instantiations&quot; title=&quot;CppBuildAnalyzer's Main.cpp with template instantiations&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See that huge amount of small entries? Those are template instantiations! And they can be part of any file, so when you include some file you also get which templates get instantiated.&lt;/p&gt;

&lt;p&gt;However, have you noticed the small &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackEndPass&lt;/code&gt; to the right? It’s got no children, hasn’t it? That’s because we’ve built a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Release&lt;/code&gt; version which has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LTCG&lt;/code&gt; enabled! Let’s take a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Linker&lt;/code&gt; activity:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-4/ltcg.png&quot; alt=&quot;Link Time Code Generation&quot; title=&quot;Link Time Code Generation&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function&lt;/code&gt; activities get compiled! In a previous graph we saw them as part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackEndPass&lt;/code&gt; activity, but it didn’t have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LTCG&lt;/code&gt; enabled.&lt;/p&gt;

&lt;p&gt;Also, it looks like Visual Studio 2019 also adds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Thread&lt;/code&gt; activities between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodeGeneration&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function&lt;/code&gt; activities!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This exploration of the C++ Build Insights SDK helped me take more informed decisions when investigating C++ compile times and I’m sure I’ll be using it in the future.&lt;/p&gt;

&lt;p&gt;Again, let me thank the team that made the SDK possible, and &lt;a href=&quot;https://twitter.com/KevinCadieuxMS&quot;&gt;@KevinCadieuxMS&lt;/a&gt; in particular!&lt;/p&gt;

&lt;p&gt;To write this post I built a tool that’s now &lt;a href=&quot;https://github.com/MetanoKid/cpp-build-analyzer&quot; target=&quot;_blank&quot;&gt;available on GitHub&lt;/a&gt; for everyone to try!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="C++" /><category term="Visual Studio" /><category term="Profiling" /><category term="Flame graph" /><category term="MSVC" /><category term="C++ Build Insights" /><category term="SDK" /><category term="vcperf" /><summary type="html">Let's investigate the SDK and find interesting data!</summary></entry><entry><title type="html">Improving C++ compile times using flame graphs</title><link href="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-3/" rel="alternate" type="text/html" title="Improving C++ compile times using flame graphs" /><published>2020-03-30T00:00:00+00:00</published><updated>2020-03-30T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-3</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-3/">&lt;p&gt;In the last posts we’ve explored ways to know how long a C++ build takes and how to create flame graphs out of MSBuild’s execution.&lt;/p&gt;

&lt;p&gt;This time we’ll check several examples and try make more informed decisions to improve our build times. We’ll see a lot of examples, so expect it to be an image-heavy post!&lt;/p&gt;

&lt;h1 id=&quot;understanding-msbuild-flame-graphs&quot;&gt;Understanding MSBuild flame graphs&lt;/h1&gt;

&lt;p&gt;First of all, we should learn how to read these flame graphs. This one shows a sample build of my (unreleased) GameBoy emulator side project. It’s a Visual Studio 2015 solution that mixes C++, C++/CLI and C# code:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/gameboy-emulator-flame-graph.png&quot; alt=&quot;GameBoy emulator flame graph&quot; title=&quot;GameBoy emulator's flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In this graph we’ve got:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pid&lt;/code&gt;: these are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt; values as reported by MSBuild. Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt; starts at 1, we’ve used index 0 to tag the build itself. They don’t exactly represent processors, cores or threads (we’ll see an example with a ton of timelines at the end of the post).&lt;/li&gt;
  &lt;li&gt;Several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSBuild timeline&lt;/code&gt;: they represent different execution hierarchies. Very important notice: they are &lt;strong&gt;absolutely made up&lt;/strong&gt;. MSBuild reports entries (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt;) living in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt;, but some of them don’t share the same hierarchy! For these cases, I decided to separate them into different timelines. We talked about hierarchies in the previous post.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a bit hard to explore hierarchies with screenshots, but let’s edit the image above to help us understand what’s going on:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-flame-graph-top-projects.png&quot; alt=&quot;GameBoy emulator flame graph: top-level projects&quot; title=&quot;GameBoy emulator's flame graph: top-level projects&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;These are the two top-level projects within the solution. In this case, both create an executable (one for the emulator itself, one for the test suite).&lt;/p&gt;

&lt;p&gt;Did you notice they’re &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.metaproj&lt;/code&gt; projects? That means they’re created implicitly from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sln&lt;/code&gt; file because they have dependencies (more info in the previous post). See how both of them have two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSBuild&lt;/code&gt; tasks? The leftmost task builds its dependencies while the rightmost build the project itself.&lt;/p&gt;

&lt;p&gt;In the image, the uppermost group labeled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindows.vcxproj.metaproj&lt;/code&gt;. Its dependencies get built within the same timeline and then builds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindows.vcxproj&lt;/code&gt; down at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 2&lt;/code&gt;. This was kind of surprising for me at first (&lt;em&gt;why not building it within the same timeline, similar to its dependencies?&lt;/em&gt;) but that’s how MSBuild reports it.&lt;/p&gt;

&lt;p&gt;Meanwhile, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Test.vcxproj.metaproj&lt;/code&gt; is building in the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt; but in a different timeline: they build in parallel because they don’t depend on each other. It also waits for its dependencies (both projects share the same ones), then builds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Test.vcxproj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And what about these dependencies? Let’s zoom in a bit into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindows.vcxproj.metaproj&lt;/code&gt; and annotate the graph:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-flame-graph-dependencies.png&quot; alt=&quot;GameBoy emulator flame graph: dependencies&quot; title=&quot;GameBoy emulator's flame graph: dependencies&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindows.vcxproj.metaproj&lt;/code&gt;. It starts in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 1, timeline 0&lt;/code&gt; and features two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSBuild&lt;/code&gt; tasks. The rightmost one builds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindows.vcxproj&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 2, timeline 0&lt;/code&gt; (I guess it’s because MSBuild scheduled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Test.vcxproj.metaproj&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 1&lt;/code&gt;, so this one got moved to a separate one).&lt;/li&gt;
  &lt;li&gt;Group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GameBoy.vcxproj.metaproj&lt;/code&gt;. Everything it does lives in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 1, timeline 0&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogLibrary.vcxproj.metaproj&lt;/code&gt; and, surprisingly, starts in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 1, timeline 0&lt;/code&gt; but does all of its work in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 2, timeline 0&lt;/code&gt;. No idea why this jump, that’s how MSBuild scheduled them.&lt;/li&gt;
  &lt;li&gt;Group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowBridge.vcxproj&lt;/code&gt;. Although it has a dependency, there’s no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vcxproj.metaproj&lt;/code&gt; this time. I guess it’s because it depends on a C# project? It does all of its work at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 2, timeline 0&lt;/code&gt;, but I’ve painted the group bigger to fit the next one.&lt;/li&gt;
  &lt;li&gt;Group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5&lt;/code&gt; is the last dependency: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI.csproj&lt;/code&gt;. It gets built in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 1, timeline 1&lt;/code&gt; (MSBuild reports it shares &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId 1&lt;/code&gt; with other entries but they aren’t part of the same hierarchy, that’s why it goes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timeline 1&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I really hope it made things a bit more clear.&lt;/p&gt;

&lt;p&gt;We can ask MSBuild to &lt;em&gt;limit parallel projects to 1&lt;/em&gt; and thus flatten them:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/gameboy-emulator-one-parallel-project-flame-graph.png&quot; alt=&quot;GameBoy emulator flame graph, one parallel project&quot; title=&quot;GameBoy emulator's flame graph, one parallel project&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Leftmost entries are the ones that build first while depth represents dependencies.&lt;/p&gt;

&lt;h1 id=&quot;adding-more-info-via-msvc-flags&quot;&gt;Adding more info via MSVC flags&lt;/h1&gt;

&lt;p&gt;In the previous post we explored some MSVC flags that added extra timing information to our build, so we should try using them!&lt;/p&gt;

&lt;h2 id=&quot;bt&quot;&gt;/Bt+&lt;/h2&gt;

&lt;p&gt;This flag produces this kind of output:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;1&amp;gt;  File.cpp
1&amp;gt;  time(Z:\path\to\compiler\c1xx.dll)=0.39427s &amp;lt; 1617765075910 - 1617766036302 &amp;gt; BB [Z:\path\to\File.cpp]
1&amp;gt;  time(Z:\path\to\compiler\c2.dll)=0.06475s &amp;lt; 1617766053824 - 1617766211553 &amp;gt; BB [Z:\path\to\File.cpp]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These messages represent three parts of a file compilation: the start, the end of the compiler’s front-end and the end of the compiler’s back-end. With this, we can create our own entries in the graph and represent each compilation!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-flame-graph-btplus-no-mp.png&quot; alt=&quot;Using /Bt+ MSVC flag&quot; title=&quot;Using /Bt+ MSVC flag&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Because these entries are &lt;strong&gt;absolutely made up&lt;/strong&gt;, I’ve labeled its timeline as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Post-processed timeline&lt;/code&gt; to separate them from the raw MSBuild data.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; output, for this graph, looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;File1.cpp
time(c1xx.dll) [...] [File1.cpp]
File2.cpp
time(c1xx.dll) [...] [File2.cpp]
[...]
time(c2.dll) [...] [File2.cpp]
time(c2.dll) [...] [File1.cpp]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This means it’s executing the front-end for each file and then the back-end (and in reverse order)! That means we’re not compiling files in parallel, what a mess!&lt;/p&gt;

&lt;p&gt;Turns out, this is the default behavior when you create a new project in Visual Studio 2015. Let’s fix it by adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/MP&lt;/code&gt; flag:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/mp-flag.png&quot; alt=&quot;Enabling /MP&quot; title=&quot;Enabling /MP&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We also have to turn off &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Gm&lt;/code&gt; because it’s incompatible with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/MP&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gm-minus-flag.png&quot; alt=&quot;Disabling /Gm&quot; title=&quot;Disabling /Gm&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s now rebuild the solution and check again!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-flame-graph-btplus-with-mp.png&quot; alt=&quot;Using /Bt+ and /MP MSVC flags&quot; title=&quot;Using /Bt+ and /MP MSVC flags&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s better! Now we can see how there’s as many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Post-processed timeline&lt;/code&gt; as logical cores. This is the default value, it can be tweaked as well.&lt;/p&gt;

&lt;p&gt;Again, because these timelines are made up, it’s not set in stone which file gets compiled in which core. All we have are MSBuild messages saying their compilation started, front-end execution finished and back-end execution finished. With that, we’ve filled the gaps in the logical cores.&lt;/p&gt;

&lt;p&gt;Here we hit one big issue: every message within the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; task in this case) share the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildEventContext&lt;/code&gt; and other data we could use to tell messages apart. Luckily, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; messages say which file they refer to so we can know which ones are related. We’ll come back to this issue later on, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/d1reportTime&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s use another project now! This is what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; has to say when we build the solution from &lt;a href=&quot;https://randomascii.wordpress.com/2014/03/22/make-vc-compiles-fast-through-parallel-compilation/&quot; target=&quot;_blank&quot;&gt;this blog post&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/random-ascii-bt-plus.png&quot; alt=&quot;Random ASCII's trace with /Bt+&quot; title=&quot;Random ASCII's trace with /Bt+&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;First of all: no project has dependencies. That’s why we don’t find any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vcxproj.metaproj&lt;/code&gt; entries. Thanks to this, and because we’ve built the full solution, each project lies into its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt;. Let’s explore each one:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompileNonParallel.vcxproj&lt;/code&gt;: it’s doesn’t have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/MP&lt;/code&gt; enabled (we only see one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Post-processed timeline&lt;/code&gt;) and it defines groups of files with different compiler flags (it has several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompileMoreParallel.vcxproj&lt;/code&gt;: it has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/MP&lt;/code&gt; enabled but still defines groups of files with different compiler flags. That’s why we see parallel compilations in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks with more than one file, but still a lot of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompileMostParallel.vcxproj&lt;/code&gt;: all files share the same compiler flags except the pre-compiled header, that’s why we see two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, what does this &lt;em&gt;different compiler flags&lt;/em&gt; have to do with having several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks? That’s because MSBuild creates batches of files that can be compiled with the same flags and then spawn as many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks to execute the compiler. When they’re done, a new batch begins.&lt;/p&gt;

&lt;p&gt;In the case of pre-compiled headers, you must compile one file with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Yc&lt;/code&gt; flag to create the PCH while other files must compile with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Yu&lt;/code&gt; flag to use that file. Because they’ve got different flags, MSBuild creates two batches.&lt;/p&gt;

&lt;h3 id=&quot;bonus-files-with-the-same-name&quot;&gt;Bonus: files with the same name&lt;/h3&gt;

&lt;p&gt;Let’s suppose you’ve got a project with a number of files spread into folders. And let’s say two of the files you’ve got use the same name: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.cpp&lt;/code&gt;. When you compile the project you get this warning:&lt;/p&gt;

&lt;p class=&quot;notice--primary&quot;&gt;Two or more files with the name of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.cpp&lt;/code&gt; will produce outputs to the same location. This can lead to an incorrect build result. The files involved are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src\Folder1\File.cpp&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src\Folder2\File.cpp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is because the default project configuration creates all intermediate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.obj&lt;/code&gt; files in the same folder. When it compiles the second &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File.cpp&lt;/code&gt; file, its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.obj&lt;/code&gt; file overwrites the former one. If you queried Google and checked &lt;a href=&quot;https://stackoverflow.com/a/3731577/1257656&quot; target=&quot;_blank&quot;&gt;the first answer in Stack Overflow&lt;/a&gt;, you’d modify the project with this property:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ObjectFileName&amp;gt;&lt;/span&gt;$(IntDir)/%(RelativeDir)/&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ObjectFileName&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And this is its trace:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/object-file-name-relative-dir.png&quot; alt=&quot;Setting %(RelativeDir) to ObjectFileName&quot; title=&quot;Setting %(RelativeDir) to ObjectFileName&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yes, it built without issues but now we will have as many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks as folders in our project! This is &lt;strong&gt;the wrong approach&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Alright, that was a synthetic test, but now imagine you have a processor with 8 or 16 logical cores and the same kind of project. If you’ve got only a handful of files per folder you’d be wasting most of those cores because batches won’t have as many files! You’re destroying parallelism!&lt;/p&gt;

&lt;p&gt;You better fix your physical structure instead of doing this, or your build times will suffer. I once decreased the Rebuild time of a project by almost 2 minutes (2 minutes!) with just this change. It can get serious.&lt;/p&gt;

&lt;h2 id=&quot;time&quot;&gt;/time+&lt;/h2&gt;

&lt;p&gt;Let’s move onto a linker flag we talked about in the previous post:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-flame-graph-time-plus-debug.png&quot; alt=&quot;GameBoy emulator flame graph: /time+ Debug&quot; title=&quot;GameBoy emulator flame graph: /time+ Debug&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Debug|x64&lt;/code&gt; compilation. Not many info, really. What about a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Release|x64&lt;/code&gt; compilation?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-flame-graph-time-plus-release.png&quot; alt=&quot;GameBoy emulator flame graph: /time+ Release&quot; title=&quot;GameBoy emulator flame graph: /time+ Release&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;By default, Release configurations enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/LTCG&lt;/code&gt; (Link Time Code Generation). It first loads all of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.obj&lt;/code&gt; files (the small entries to the left of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Pass 1&lt;/code&gt;) and then generates more optimized code (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LTCG CodeGen&lt;/code&gt; entry).&lt;/p&gt;

&lt;h2 id=&quot;d1reporttime&quot;&gt;/d1reportTime&lt;/h2&gt;

&lt;p&gt;This is the last flag we’ll be adding to get extra data (check previous post for more info). And it comes with two issues:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It’s only available from Visual Studio 2017 version of MSVC: this means we need to upgrade the GameBoy emulator project we’ve been using to make it work. Because we were already using MSBuild 15, we can build both VS2015 and VS2017 C++ solutions with the same tool!&lt;/li&gt;
  &lt;li&gt;It outputs a huge amount of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Message&lt;/code&gt; tasks for each file and we can’t relate messages to each other (i.e. their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildEventContext&lt;/code&gt; and other identifiable data match, but they don’t say which file they refer to like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; does). Because files are getting compiled in parallel we’ll get mixed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Message&lt;/code&gt; tasks! We need to break parallelism to be able to build a hierarchy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let’s first upgrade our project and then ensure we &lt;strong&gt;only compile one file at a time&lt;/strong&gt;. Doing so isn’t a hack either, that’s what the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/showIncludes&lt;/code&gt; MSVC flag does (it shows a warning saying so, although it doesn’t get mentioned in &lt;a href=&quot;https://docs.microsoft.com/cpp/build/reference/showincludes-list-include-files&quot; target=&quot;_blank&quot;&gt;the official docs&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Let’s take an example now!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-d1reportTime.png&quot; alt=&quot;GameBoy emulator flame graph: /d1reportTime&quot; title=&quot;GameBoy emulator flame graph: /d1reportTime&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is one of my test files: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoadAIntoAddressHL.cpp&lt;/code&gt;. As reported by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/d1reportTime&lt;/code&gt;, the front-end executes three sections: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Include Headers&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Definitions&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function Definitions&lt;/code&gt;. Again, all these entries are made up and that’s why they are in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Post-processed timeline&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;bonus-bt-and-d1reporttime-timing-flaw&quot;&gt;Bonus: /Bt+ and /d1reportTime timing flaw&lt;/h3&gt;

&lt;p&gt;Let’s take the combined output for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/d1reportTime&lt;/code&gt; for this file and remove &lt;em&gt;a lot&lt;/em&gt; of the messages, let’s just keep timing ones:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;[...]
LoadAIntoAddressHL.cpp
Include Headers:
  [...]
  Total: 0.591067s
Class Definitions:
  [...]
  Total: 0.178967s
Function Definitions:
  [...]
  Total: 0.511502s
time(Z:\path\to\compiler\c1xx.dll)=1.17362s &amp;lt; 2283035638380 - 2283038497179 &amp;gt; [Z:\path\to\LoadAIntoAddressHL.cpp]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let’s sum &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/d1reportTime&lt;/code&gt; sections: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.591067s + 0.178967s + 0.511502s = ‭1.281536‬s&lt;/code&gt;. However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; reports the front-end took &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.17362s&lt;/code&gt;! Disaster!&lt;/p&gt;

&lt;p&gt;If we were to use these times in the graph as they’re reported, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function Definitions&lt;/code&gt; entry would overflow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c1xx.dll&lt;/code&gt;. To fix it I decided to scale down each child of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c1xx.dll&lt;/code&gt; proportionally so all of them fit. This was a compromise, though: their times aren’t real anymore but still give you an idea of their relative impact.&lt;/p&gt;

&lt;h1 id=&quot;adding-pre-compiled-headers-to-the-mix&quot;&gt;Adding pre-compiled headers to the mix&lt;/h1&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/d1reportTime&lt;/code&gt; data at hand, let’s add this PCH to the project and check how it changes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#pragma once
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;vector&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;iomanip&amp;gt;
#include &amp;lt;sstream&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/gameboy-emulator-d1reportTime-PCH.png&quot; alt=&quot;GameBoy emulator flame graph: /d1reportTime with PCH&quot; title=&quot;GameBoy emulator flame graph: /d1reportTime with PCH&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;First of all, we can see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Include Headers&lt;/code&gt; section features a smaller number of files and hierarchies: the biggest ones we had came from the STL! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Definitions&lt;/code&gt; also has less entries: we can even read some of them at the same zoom level! And what about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function Definitions&lt;/code&gt;? It’s got far less entries now!&lt;/p&gt;

&lt;p&gt;No wonder why the time spent on this file went down from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.174s&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.161s&lt;/code&gt;! Why don’t we compare how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Test.vcxproj&lt;/code&gt; project build time changed with the PCH?&lt;/p&gt;

&lt;p&gt;This is how it looked before the PCH:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/test-project-d1reporttime-pre-pch.png&quot; alt=&quot;Test.vcxproj without PCH with /d1reportTime&quot; title=&quot;Test.vcxproj without PCH with /d1reportTime&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s add the PCH now:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/test-project-d1reporttime-post-pch.png&quot; alt=&quot;Test.vcxproj with PCH with /d1reportTime&quot; title=&quot;Test.vcxproj with PCH with /d1reportTime&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See how the PCH has cut a lot of depth on each file? Also, the full project went down from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2m17s&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;49s&lt;/code&gt;, and that’s with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/MP&lt;/code&gt; turned off! What if we turned it on?&lt;/p&gt;

&lt;p&gt;This is how it looked before the PCH:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/test-project-pre-pch.png&quot; alt=&quot;Test.vcxproj without PCH&quot; title=&quot;Test.vcxproj without PCH&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s add the PCH now:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/test-project-post-pch.png&quot; alt=&quot;Test.vcxproj with PCH&quot; title=&quot;Test.vcxproj with PCH&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s gone from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1m08s&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;27s&lt;/code&gt;! Also, have you noticed how each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c1xx.dll&lt;/code&gt; entry has shrunk in size?&lt;/p&gt;

&lt;p&gt;To sum up: we can check build times thanks to these flame graphs but also visualize the impact of our changes!&lt;/p&gt;

&lt;h1 id=&quot;extra-examples&quot;&gt;Extra examples&lt;/h1&gt;

&lt;p&gt;To finish this post I’ve built a couple of projects from GitHub to see how their flame graphs look like. Let’s check them!&lt;/p&gt;

&lt;h2 id=&quot;rapidjson&quot;&gt;RapidJSON&lt;/h2&gt;

&lt;p&gt;This is the flame graph for &lt;a href=&quot;https://github.com/Tencent/rapidjson&quot; target=&quot;_blank&quot;&gt;RapidJSON&lt;/a&gt; when building the whole solution in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Debug|x64&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/time+&lt;/code&gt; enabled. Be warned, it’s large:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/example-rapidjson.png&quot; alt=&quot;RapidJSON flame graph&quot; title=&quot;RapidJSON flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With the info from this post, can you tell whether &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/MP&lt;/code&gt; is enabled for this build?&lt;/p&gt;

&lt;p&gt;For reference, this is what &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ivson4.ParallelBuildsMonitor-18691&quot; target=&quot;_blank&quot;&gt;Paralel Builds Monitor&lt;/a&gt; has to say of the build:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/example-rapidjson-parallel-builds-monitor.png&quot; alt=&quot;RapidJSON build as seen by Parallel Builds Monitor&quot; title=&quot;RapidJSON build as seen by Parallel Builds Monitor&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See how the maximum number of projects building in parallel is 4? That’s the number of logical cores in the machine I used to build it.&lt;/p&gt;

&lt;h2 id=&quot;google-test&quot;&gt;Google Test&lt;/h2&gt;

&lt;p&gt;This one is for &lt;a href=&quot;https://github.com/google/googletest&quot; target=&quot;_blank&quot;&gt;Google Test&lt;/a&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Debug|x64&lt;/code&gt;. While RapidJSON built 28 projects, this one builds 80! We’ll have to see it as a downscaled gif instead of a huge screenshot:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-3/google-test-flame-graph.gif&quot; alt=&quot;Google Test flame graph&quot; title=&quot;Google Test flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This series has focused on exploring and understanding MSBuild to create flame graphs we could view in Google Chrome’s trace viewer. We’ve learned about MSVC flags and other interesting tools as well. Thanks to them we can make more informed decisions when improving build times and be able to measure their impact.&lt;/p&gt;

&lt;p&gt;I hope any of this info was useful for you, it definitely was for me.&lt;/p&gt;

&lt;p&gt;Thank you for your time, dear reader!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Update #1: I’ve decided to &lt;a href=&quot;https://github.com/MetanoKid/msbuild-flame-graph&quot; target=&quot;_blank&quot;&gt;release this tool at GitHub&lt;/a&gt; so anyone can have a try. Thanks for all the support!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="C++" /><category term="CSharp" /><category term="Visual Studio" /><category term="MSBuild" /><category term="Profiling" /><category term="Flame graph" /><category term="MSVC" /><category term="Bt+" /><category term="time+" /><category term="d1reportTime" /><summary type="html">Now we can create flame graphs from MSBuild executions, let's put them to use!</summary></entry><entry><title type="html">Understanding MSBuild to create flame graphs</title><link href="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-2/" rel="alternate" type="text/html" title="Understanding MSBuild to create flame graphs" /><published>2020-03-27T00:00:00+00:00</published><updated>2020-03-27T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-2</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-2/">&lt;p&gt;I love side projects. You have a problem you want to solve, spend some time thinking about how you’d do it and then start working on a solution that &lt;em&gt;mostly works&lt;/em&gt;. When you’ve calmed the itch that started it all, it becomes a &lt;em&gt;product&lt;/em&gt; and you start losing interest on it. A new side projects pops in, the cycle repeats.&lt;/p&gt;

&lt;p&gt;But this time I managed to finish one!&lt;/p&gt;

&lt;p&gt;Over a year ago I started a side project to create a flame graph out of a MSBuild execution. It was inspired by &lt;a href=&quot;https://twitter.com/aras_p&quot;&gt;@aras_p&lt;/a&gt;’s &lt;a href=&quot;https://aras-p.info/blog/2019/01/16/time-trace-timeline-flame-chart-profiler-for-Clang/&quot; target=&quot;_blank&quot;&gt;blog post&lt;/a&gt;. Thanks again for everything you’ve written in your blog!&lt;/p&gt;

&lt;p&gt;This post serves as a summary of what I learned while developing this tool. I thought it would be a shorter post but then got out of control! We’ll have an extra post fiddling with compiler flags and project configurations to show a lot of examples!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/msbuild-flame-graph.png&quot; alt=&quot;MSBuild to flame graph&quot; title=&quot;MSBuild flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Some of the examples in this post will feature my (unreleased) GameBoy emulator (yeah, one of those abandoned side projects) to illustrate some points. This way, we can see some real data and not just synthetic tests.&lt;/p&gt;

&lt;h1 id=&quot;the-background&quot;&gt;The background&lt;/h1&gt;

&lt;p&gt;When I started looking for ways to investigate build times I ended up with some useful MSVC flags and some Visual Studio options (check previous post in the series for more).&lt;/p&gt;

&lt;p&gt;It basically looked like I could compile a solution, parse its output and start working from there. And it didn’t seem very crazy, people build tools around that! Just open Visual Studio’s Developer Command Prompt and type:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;devenv.com Z:\path\to\solution.sln /Rebuild&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’ve used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devenv.com&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;devenv.exe&lt;/code&gt; because it writes to console.&lt;/p&gt;

&lt;p&gt;We’ll get something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;3&amp;gt;  [...]
4&amp;gt;------ Rebuild All started: Project: GameBoy, Configuration: Debug x64 ------
4&amp;gt;  Cartridge.cpp
4&amp;gt;  [...]
========== Rebuild All: 6 succeeded, 0 failed, 0 skipped ==========&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is basically like building the solution in Visual Studio and copying the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Output&lt;/code&gt; panel. However, that’s all you have. I guess it isn’t enough for us!&lt;/p&gt;

&lt;p&gt;In the previous post I mentioned Visual Studio Extensions use an SDK that lets you hook to MSBuild events and perform your own logic. That means Visual Studio is using MSBuild under the hood, doesn’t it?&lt;/p&gt;

&lt;p&gt;Let’s try to build our solution with MSBuild directly (again, within Visual Studio’s Developer Command Prompt):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;msbuild.exe Z:\path\to\solution.sln /t:Rebuild&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will rebuild our solution and dump a lot of information to console. It looks very much like setting &lt;em&gt;MSBuild project build output verbosity&lt;/em&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Normal&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Detailed&lt;/code&gt; in Visual Studio’s Options window!&lt;/p&gt;

&lt;p&gt;We’re getting closer, and &lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/msbuild&quot; target=&quot;_blank&quot;&gt;MSBuild official documentation&lt;/a&gt; has a lot more information on the topic. The key section, for us, will be &lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/msbuild-api&quot; target=&quot;_blank&quot;&gt;using MSBuild programmatically&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;the-goal&quot;&gt;The goal&lt;/h1&gt;

&lt;p&gt;Now that we know we can invoke MSBuild ourselves, parsing its output would be complex and still not give us enough data (i.e. no timestamps). Since there’s some kind of API to deal with it programmatically, let’s explore what it can offer!&lt;/p&gt;

&lt;h1 id=&quot;c-api&quot;&gt;C# API&lt;/h1&gt;

&lt;p&gt;At first, when I started building this tool, I was amazed at how little information I could find on how to call MSBuild from C# code. All I found were incomplete or unrelated issues on the MSDN forums, questions without accepted answers at Stack Overflow and a very low number of uses at GitHub.&lt;/p&gt;

&lt;p&gt;I spent a lot of time trying to make it work, failing, trying again, mostly working but only for C++ solutions and not C# ones…&lt;/p&gt;

&lt;p&gt;In the end, invoking MSBuild just takes these lines:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;globalProperties&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Configuration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Debug&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Platform&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x64&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;BuildRequestData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BuildRequestData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Z:\\path\\to\\solution.sln&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                             &lt;span class=&quot;n&quot;&gt;globalProperties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                             &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                             &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Rebuild&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                                             &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// not providing this default ProjectCollection causes unordered builds&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ProjectCollection&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;projectCollection&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProjectCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BuildParameters&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BuildParameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;projectCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BuildResult&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DefaultBuildManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OverallResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildResultCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// yay!&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildResultCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Failure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// d'oh!&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Simple, right? Well… &lt;em&gt;no&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For it to work you need these &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildRequestData&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildParameters&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildManager&lt;/code&gt; classes. And this is where the pain started for me.&lt;/p&gt;

&lt;h2 id=&quot;reference-msbuild-assemblies&quot;&gt;Reference MSBuild assemblies&lt;/h2&gt;

&lt;p&gt;By the time I started working on this tool I was using Visual Studio 2015 and I didn’t know where to find any of these assemblies. I only knew they were part of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.Build&lt;/code&gt; packages, as stated in the official docs. So I tried adding a Reference to them via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Framework&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/msbuild-assemblies-framework.png&quot; alt=&quot;MSBuild assemblies via Framework&quot; title=&quot;Assemblies via Framework&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note it says version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4.0.0.0&lt;/code&gt;, I didn’t even know which version I needed! This happened like a year ago so I may have forgotten, but I think it worked for a while until I tried to compile a different kind of project. In any case, I ended up referencing assemblies via the Extensions page:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/msbuild-assemblies-extensions.png&quot; alt=&quot;MSBuild assemblies via Extensions&quot; title=&quot;Assemblies via Extensions&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note it says version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;14.0.0.0&lt;/code&gt;. Still, no idea why they’re different, but this one worked correctly (and then I knew I was using MSBuild 14).&lt;/p&gt;

&lt;h3 id=&quot;bonus-binding-redirects&quot;&gt;Bonus: binding redirects&lt;/h3&gt;

&lt;p&gt;When I thought everything was set, I tried to build my first project and… it failed.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;The &quot;Message&quot; task could not be loaded from the assembly Microsoft.Build.Tasks.Core, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. [...]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This cryptic message hit me like a stone. &lt;em&gt;Why can’t it find it? It compiled and I’m executing the tool now!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Oh, well, turns out you have to apply binding redirects to make it build Visual Studio 2015 solutions. More info on the &lt;a href=&quot;https://docs.microsoft.com/dotnet/framework/configure-apps/redirect-assembly-versions&quot; target=&quot;_blank&quot;&gt;official docs&lt;/a&gt;. I’m a C++ programmer and wasn’t aware of this requirement, I guess .NET programmers are used to it!&lt;/p&gt;

&lt;p&gt;I ended up adding this kind of entries to my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.config&lt;/code&gt; file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;runtime&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;assemblyBinding&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;urn:schemas-microsoft-com:asm.v1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependentAssembly&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;assemblyIdentity&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.Build&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;culture=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;neutral&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;publicKeyToken=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b03f5f7f11d50a3a&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;bindingRedirect&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;oldVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.0.0.0-99.9.9.9&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;newVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;14.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependentAssembly&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- more bindings for Microsoft.Build.Framework and other assemblies! --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/assemblyBinding&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/runtime&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;https://knowyourmeme.com/memes/i-have-no-idea-what-im-doing&quot;&gt;&lt;img src=&quot;https://i.kym-cdn.com/photos/images/newsfeed/000/234/765/b7e.jpg&quot; alt=&quot;I have no idea what I'm doing&quot; title=&quot;I have no idea what I'm doing&quot; class=&quot;align-center&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;bonus-msbuild-15-and-wpf-projects&quot;&gt;Bonus: MSBuild 15 and WPF projects&lt;/h3&gt;

&lt;p&gt;Everything seemed to work… until I tried to migrate to MSBuild 15 a year later (so I could build Visual Studio 2017 solutions). There’s &lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/updating-an-existing-application&quot; target=&quot;_build&quot;&gt;an official guide&lt;/a&gt; to do so (thank you!).&lt;/p&gt;

&lt;p&gt;Apparently, versions under MSBuild 15 were bound to their Visual Studio installation and the new recommended way is to pull them via NuGet packages so they’re separate.&lt;/p&gt;

&lt;p&gt;With that in place I was able to build VS2017 C++ projects, but had no luck with C# ones.&lt;/p&gt;

&lt;p&gt;My GameBoy emulator is built in C++ but uses &lt;a href=&quot;https://metanokid.github.io/coding-scars/log-window-0/&quot;&gt;a Logger built in WPF&lt;/a&gt;. Turns out, WPF uses MSBuild itself to process &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.xaml&lt;/code&gt; files (its UI-definition files). That means it tries to spawn and wait for a new MSBuild process within ours! That results in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unknown build error: object reference not set to an instance of an object&lt;/code&gt;. Yes, a null pointer exception is all of the info you have to diagnose it. Good.&lt;/p&gt;

&lt;p&gt;The fix is quite simple, however! Add this property to you WPF project:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;AlwaysCompileMarkupFilesInSeparateDomain&amp;gt;&lt;/span&gt;false&lt;span class=&quot;nt&quot;&gt;&amp;lt;/AlwaysCompileMarkupFilesInSeparateDomain&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And it will use the same MSBuild instance that invoked the build. &lt;em&gt;Voilà&lt;/em&gt;!&lt;/p&gt;

&lt;h2 id=&quot;get-build-data&quot;&gt;Get build data&lt;/h2&gt;

&lt;p&gt;Alright! We’ve managed to make a solution build but we have nothing else to work with! Fear not, the API defines the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ILogger&lt;/code&gt; interface and the basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Logger&lt;/code&gt; class for us! More info on the &lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/build-loggers&quot; target=&quot;_blank&quot;&gt;Build Loggers docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s just take everything we can get from the build:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AllMessagesLogger&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IEventSource&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eventSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eventSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnyEventRaised&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnAnyMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnAnyMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildEventArgs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And we can add this logger to the build by modifying the original code with this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;BuildParameters&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BuildParameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Loggers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AllMessagesLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’ll now be printing the message associated to every event MSBuild emits. And believe me, there’s a ton of messages!&lt;/p&gt;

&lt;p&gt;Still, there are some interesting things we should investigate.&lt;/p&gt;

&lt;h3 id=&quot;which-events-can-we-hook-to&quot;&gt;Which events can we hook to?&lt;/h3&gt;

&lt;p&gt;This is the definition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEventSource&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IEventSource&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildMessageEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MessageRaised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildErrorEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ErrorRaised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildWarningEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WarningRaised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildStartedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildStarted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildFinishedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildFinished&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProjectStartedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProjectStarted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProjectFinishedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProjectFinished&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TargetStartedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TargetStarted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TargetFinishedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TargetFinished&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TaskStartedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TaskStarted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TaskFinishedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TaskFinished&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomBuildEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomEventRaised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildStatusEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StatusEventRaised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AnyEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AnyEventRaised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nice, our old friends the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt;! We’ll come back to them in a bit and explore their relationships.&lt;/p&gt;

&lt;p&gt;For now, just remember you can bind to different kind of events to get only what you’re interested in.&lt;/p&gt;

&lt;h3 id=&quot;buildeventargs&quot;&gt;BuildEventArgs&lt;/h3&gt;

&lt;p&gt;This is the base class for these events. Of all members it’s got we’re interested in these ones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timestamp&lt;/code&gt;: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateTime&lt;/code&gt; when the event was emitted (the &lt;em&gt;when&lt;/em&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Message&lt;/code&gt;: the text you’ve already read within Visual Studio’s Output panel (the &lt;em&gt;what&lt;/em&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildEventContext&lt;/code&gt;: the context this event lives in (the &lt;em&gt;where&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s try to understand what’s the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildEventContext&lt;/code&gt; then!&lt;/p&gt;

&lt;h3 id=&quot;buildeventcontext&quot;&gt;BuildEventContext&lt;/h3&gt;

&lt;p&gt;This class looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuildEventContext&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProjectContextId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NodeId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProjectInstanceId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TaskId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TargetId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BuildRequestId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SubmissionId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EvaluationId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’re only interested in the first members:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProjectContextId&lt;/code&gt; identifies this context, useful when comparing two of them.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt;, after a bit of testing, identifies the &lt;em&gt;logical timeline&lt;/em&gt; where it got executed (starts at 1). It has nothing to do with processors, cores or threads so it can get pretty high.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProjectContextId&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TargetId&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TaskId&lt;/code&gt; identify &lt;em&gt;where&lt;/em&gt; this event got executed within a hierarchy. We’ll come back to them shortly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alright, I think we can’t postpone exploring &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; anymore!&lt;/p&gt;

&lt;h2 id=&quot;projects-targets-and-tasks&quot;&gt;Projects, targets and tasks&lt;/h2&gt;

&lt;p&gt;MSBuild data is defined in XML files and there’s a hierarchy between definitions. These are the basics:&lt;/p&gt;

&lt;h3 id=&quot;project&quot;&gt;Project&lt;/h3&gt;

&lt;p&gt;You may not know it, but that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vcxproj&lt;/code&gt; project file you’ve got is an XML file with MSBuild definitions. A Visual Studio 2015 project, for example, looks like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;DefaultTargets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Build&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ToolsVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;14.0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[...]&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Label=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ProjectConfigurations&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ProjectConfiguration&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Debug|x64&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Configuration&amp;gt;&lt;/span&gt;Debug&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Configuration&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Platform&amp;gt;&lt;/span&gt;x64&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Platform&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ProjectConfiguration&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The key tag is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt;, the root of the document. You can head to the &lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/project-element-msbuild&quot; target=&quot;_blank&quot;&gt;official documentation&lt;/a&gt; for more info, but let’s just keep &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; in cache.&lt;/p&gt;

&lt;h3 id=&quot;target&quot;&gt;Target&lt;/h3&gt;

&lt;p&gt;If we continue exploring this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vcxproj&lt;/code&gt; file we’ll find this section:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemDefinitionGroup&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;'$(Configuration)|$(Platform)'=='Debug|x64'&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ClCompile&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;WarningLevel&amp;gt;&lt;/span&gt;Level3&lt;span class=&quot;nt&quot;&gt;&amp;lt;/WarningLevel&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Optimization&amp;gt;&lt;/span&gt;Disabled&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Optimization&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;PreprocessorDefinitions&amp;gt;&lt;/span&gt;_DEBUG;_LIB;%(PreprocessorDefinitions)&lt;span class=&quot;nt&quot;&gt;&amp;lt;/PreprocessorDefinitions&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;SDLCheck&amp;gt;&lt;/span&gt;true&lt;span class=&quot;nt&quot;&gt;&amp;lt;/SDLCheck&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;MinimalRebuild&amp;gt;&lt;/span&gt;true&lt;span class=&quot;nt&quot;&gt;&amp;lt;/MinimalRebuild&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ClCompile&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Link&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;SubSystem&amp;gt;&lt;/span&gt;Windows&lt;span class=&quot;nt&quot;&gt;&amp;lt;/SubSystem&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;GenerateDebugInformation&amp;gt;&lt;/span&gt;true&lt;span class=&quot;nt&quot;&gt;&amp;lt;/GenerateDebugInformation&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemDefinitionGroup&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are two tags I want you to pay attention to: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClCompile&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Link&lt;/code&gt;. Both are specialized &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt; definitions (we’ll see &lt;em&gt;how&lt;/em&gt; in a moment). A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt; lives within a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; and groups &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; definitions together in a given order. You can read more in the &lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/msbuild-targets&quot; target=&quot;_blank&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;task&quot;&gt;Task&lt;/h3&gt;

&lt;p&gt;Finally, tasks execute the real logic behind all these definitions. They can create directories (&lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/makedir-task&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MakeDir&lt;/code&gt; task&lt;/a&gt;), compile code (&lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/cl-task&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; task&lt;/a&gt;) or invoke other projects (&lt;a href=&quot;https://docs.microsoft.com/visualstudio/msbuild/msbuild-task&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSBuild&lt;/code&gt; task&lt;/a&gt;), for example.&lt;/p&gt;

&lt;p&gt;We could faithfully believe they’re part of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt;, but let’s have a look ourselves, shall we? If you have a basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vcxproj&lt;/code&gt; you won’t see any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt;, but you’ll get this entry:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Import&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Project=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$(VCTargetsPath)\Microsoft.Cpp.targets&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you were to find that file, you’d see it has some definitions that point to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.Cpp.Current.targets&lt;/code&gt; and you could continue down the rabbit hole until you get to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.CppCommon.targets&lt;/code&gt;. Inside that file you can find the definition of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClCompile&lt;/code&gt; target:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;          
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Target&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ClCompile&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;'@(ClCompile)' != ''&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;DependsOnTargets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SelectClCompile&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;CL&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[...]&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;CL&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[...]&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;          
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And that’s where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; task gets invoked!&lt;/p&gt;

&lt;p&gt;Nice, so a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; can have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt; entries and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt; groups &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; entries together (one of which can spawn other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/project-target-task-hierarchy.png&quot; alt=&quot;Project, target and task hierarchy&quot; title=&quot;Project, target and task hierarchy&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is all great, but what’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Solution&lt;/code&gt; file then?&lt;/p&gt;

&lt;h3 id=&quot;solution&quot;&gt;Solution&lt;/h3&gt;

&lt;p&gt;If we were to open a Visual Studio 2015 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sln&lt;/code&gt; file we’d find some structured text:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
[...]
Project(&quot;{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}&quot;) = &quot;GameBoy&quot;, &quot;Projects\GameBoy\GameBoy.vcxproj&quot;, &quot;{A9A3EC03-A464-4D7C-AC36-857D50CCA937}&quot;
  ProjectSection(ProjectDependencies) = postProject
    {E6C50B23-8563-4980-B0E4-DD4B0570810D} = {E6C50B23-8563-4980-B0E4-DD4B0570810D}
  EndProjectSection
EndProject
[...]
Global
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
    Debug|x64 = Debug|x64
  EndGlobalSection
  [...]
EndGlobal&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This defines which projects exist within our solution, their relationship and some other data. If we go back to our Visual Studio’s Developer Command Prompt and type:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;set MSBuildEmitSolution=1
msbuild.exe Z:\path\to\solution.sln&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’ll get several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.metaproj&lt;/code&gt; files we can open. And surprise, they are MSBuild compilant files!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ToolsVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;14.0&quot;&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;InitialTargets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ValidateSolutionConfiguration;ValidateToolsVersions;ValidateProjects&quot;&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;DefaultTargets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Build&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Target&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;GameBoy:Rebuild&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- [...] --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;See the name of the generated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Target&lt;/code&gt;? This is why we can Rebuild a project (and not the full solution) by executing:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;msbuild.exe Z:\path\to\solution.sln /t:ProjectName:Rebuild&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Great, so now that we know how MSBuild is structured, we can continue. But before we move on, this is the key takeaway from this section:&lt;/p&gt;

&lt;p class=&quot;notice--primary&quot;&gt;&lt;strong&gt;Don’t be afraid of diving as deep as you can when facing a new system.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;tying-it-all-together&quot;&gt;Tying it all together&lt;/h2&gt;

&lt;p&gt;Let’s take the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AllMessagesLogger&lt;/code&gt; we created before and run a build. Simplifying a whole lot and gracefully indenting it, we’d get something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;BuildStarted
  ProjectStarted
    TargetStarted
      TaskStarted
      TaskFinished
      TaskStarted
        ProjectStarted
          [...]
        ProjectFinished
      TaskFinished
    TargetFinished
    TargetStarted
      [...]
    TargetFinished
  ProjectFinished
BuildFinished&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Doesn’t this looks like a hierarchy to you?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Build
  Project
    Target
      Task
      Task
        Project
          [...]
    Target&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can now start building our &lt;em&gt;timeline&lt;/em&gt;!&lt;/p&gt;

&lt;h3 id=&quot;issues&quot;&gt;Issues&lt;/h3&gt;

&lt;p&gt;At first, I thought it would be enough to keep stacking events together but soon enough I found not every entry refers to the &lt;em&gt;same hierarchy&lt;/em&gt;. You may have two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; building in parallel and events get mixed up.&lt;/p&gt;

&lt;p&gt;Here’s where we go back to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BuildEventContext&lt;/code&gt;. Remember it had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProjectInstanceId&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TargetId&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TaskId&lt;/code&gt; members? Thanks to that, we can recreate the actual hierarchy!&lt;/p&gt;

&lt;p&gt;Each context will populate these values as we get deeper in the hierarchy (i.e. a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; won’t have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TargetId&lt;/code&gt; defined), with some exceptions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Build&lt;/code&gt; is a unique element with no context.&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentEventContext&lt;/code&gt; member (defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProjectStartedEvent&lt;/code&gt; class). It can be empty (it’s a top-level &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt;) or reference a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a lot of caveats in the implementation, some inconsistencies (like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; that spawns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; but that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; is finished before the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Project&lt;/code&gt; even starts), and some trial and error.&lt;/p&gt;

&lt;p&gt;But, eventually, you get to something!&lt;/p&gt;

&lt;h1 id=&quot;google-chromes-trace-viewer&quot;&gt;Google Chrome’s trace viewer&lt;/h1&gt;

&lt;p&gt;Now that we’ve got our hierarchy in memory we should dump it to some kind of file. Turns out, Google Chrome has this &lt;a href=&quot;chrome://tracing&quot; target=&quot;_blank&quot;&gt;chrome://tracing&lt;/a&gt; viewer we can use!&lt;/p&gt;

&lt;p&gt;We’ll create a JSON file with a couple of special properties that let us visualize flame graphs. The format and properties are &lt;a href=&quot;https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview&quot; target=&quot;_blank&quot;&gt;available in this doc&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;traceEvents&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Hello, flame graph!&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2000.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;I'm a child!&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;E&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;8000.0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;E&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10000.0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’ve indented each object to give you a sense of hierarchy, but they’re all children of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceEvents&lt;/code&gt;. You can load it into the viewer and this will be the result:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/trace-example.png&quot; alt=&quot;Google Chrome's trace viewer example&quot; title=&quot;Google Chrome's trace viewer example&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;flame-graphs&quot;&gt;Flame graphs&lt;/h1&gt;

&lt;p&gt;Let’s take everything, build a couple of projects and see it in action!&lt;/p&gt;

&lt;h2 id=&quot;blank-project&quot;&gt;Blank project&lt;/h2&gt;

&lt;p&gt;If you create a blank &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C++ Win32 Console Application&lt;/code&gt; in Visual Studio 2015 with the default configuration, this is how it looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/blank-project-flame-graph.png&quot; alt=&quot;Blank project flame graph&quot; title=&quot;Blank project's flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See how it has two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks? One is the pre-compiled header and the other one is the main file. We’ll see why they’re separate in the next post.&lt;/p&gt;

&lt;h2 id=&quot;gameboy-emulator&quot;&gt;GameBoy emulator&lt;/h2&gt;

&lt;p&gt;This is the trace from my GameBoy emulator (we’ll try to improve it in the next post):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/gameboy-emulator-flame-graph.png&quot; alt=&quot;GameBoy emulator flame graph&quot; title=&quot;GameBoy emulator's flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See how it’s using several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt; and each one has a number of &lt;em&gt;timelines&lt;/em&gt;? They represent projects with dependencies!&lt;/p&gt;

&lt;p&gt;The top-level Solution executes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSBuild&lt;/code&gt; task to build &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindows.vcxproj.metaproj&lt;/code&gt; (within the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt;) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Test.vcxproj.metaproj&lt;/code&gt; (in a separate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt;). Both wait for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GameBoy.vcxproj.metaproj&lt;/code&gt; to finish (although it’s unreadable in the graph), which in turn waits for another project to build…&lt;/p&gt;

&lt;p&gt;It’s a bit complex because of the (seemingly) arbitrary &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeId&lt;/code&gt; switches, but that’s how MSBuild schedules project builds!&lt;br /&gt;
Remember, these &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vcxproj.metaproj&lt;/code&gt; are generated from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sln&lt;/code&gt; file!&lt;/p&gt;

&lt;p&gt;We can force the execution to build only &lt;em&gt;one project&lt;/em&gt; in parallel, and this is the result:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/gameboy-emulator-one-parallel-project-flame-graph.png&quot; alt=&quot;GameBoy emulator flame graph, one parallel project&quot; title=&quot;GameBoy emulator's flame graph, one parallel project&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now, dependencies are much more apparent!&lt;/p&gt;

&lt;h2 id=&quot;bruce-dawsons-parallel-build&quot;&gt;Bruce Dawson’s parallel build&lt;/h2&gt;

&lt;p&gt;Finally, while investigating slow compile times I read &lt;a href=&quot;https://randomascii.wordpress.com/2014/03/22/make-vc-compiles-fast-through-parallel-compilation/&quot; target=&quot;_blank&quot;&gt;this blog post&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/BruceDawson0xB&quot; target=&quot;_blank&quot;&gt;@BruceDawson0xB&lt;/a&gt; and it helped me a lot (thank you!). He provides the project he used for the post, so I downloaded it and this is its graph:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-2/random-ascii-parallel-flame-graph.png&quot; alt=&quot;Random ASCII parallel project flame graph&quot; title=&quot;Random ASCII's parallel project flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you want to know why there are that many &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CL&lt;/code&gt; tasks, I invite you to check his blog post or wait for the next entry in the series!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;That’s all for now! We’ve seen how to invoke MSBuild from C# and use its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Logger&lt;/code&gt; to create our flame graphs.&lt;/p&gt;

&lt;p&gt;In the next post we’ll try to understand these graphs, try to diagnose possible issues, and fiddle with some MSVC flags to get extra information (I’m looking at you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Bt+&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/d1reportTime&lt;/code&gt;!).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-1/teaser-d1reporttime-flag.png&quot; alt=&quot;Teaser of /d1reportTime as a flame graph&quot; title=&quot;Teaser of /d1reportTime as a flame graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="C++" /><category term="CSharp" /><category term="Visual Studio" /><category term="MSBuild" /><category term="Profiling" /><category term="Flame graph" /><summary type="html">Let's explore how MSBuild works and how we can visualize its process</summary></entry><entry><title type="html">My journey investigating slow compile times in C++</title><link href="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-0/" rel="alternate" type="text/html" title="My journey investigating slow compile times in C++" /><published>2020-03-25T00:00:00+00:00</published><updated>2020-03-25T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-0</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-0/">&lt;p&gt;You know what’s boring? Processes that take long to complete without you interacting. Making some coffee? &lt;em&gt;I want it already!&lt;/em&gt; Doing the laundry? &lt;em&gt;If only it didn’t take hours!&lt;/em&gt; Riding a slow elevator? &lt;em&gt;Please, c’mon!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;only&lt;/em&gt; good thing about these processes taking long is being able to do something else in the meantime. And you better don’t repeat them very otften!&lt;/p&gt;

&lt;p&gt;Programmers repeat one thing way too many times a day: building the project they’re working on. And chances are you’ve come across this awesome webcomic:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://xkcd.com/303/&quot;&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/compiling.png&quot; alt=&quot;Compiling!&quot; title=&quot;Compiling!&quot; class=&quot;align-center&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yeah, at first you may smile and think &lt;em&gt;hey, it’s funny&lt;/em&gt;. However, when that happens several times a day you start thinking &lt;em&gt;oh, not again&lt;/em&gt; instead.&lt;/p&gt;

&lt;p&gt;This isn’t a pathology for a single language, platform or business: you may be a game programmer whose project takes several minutes to build (and some more to run!), or a front-end developer whose packaging and deployment process lets you have breakfast while it finishes or you may have some kind of asset in your project you need to process and wish you didn’t need to.&lt;/p&gt;

&lt;h1 id=&quot;motivation&quot;&gt;Motivation&lt;/h1&gt;

&lt;p&gt;I’ve been worrying about slow build times lately. Like, for the last couple of years.&lt;/p&gt;

&lt;p&gt;Profiling processes isn’t alien to programmers, sometimes you need to know why something is slow. However, it’s less common to profile build or deployment processes (and we repeat them very often!).&lt;/p&gt;

&lt;p&gt;Slow build times cause frustration and discourage both architecture and feature iteration: &lt;em&gt;if I modify this file I get a full rebuild, so I better not touch it&lt;/em&gt;. This costs your company increasing amounts of money: people aren’t creating new stuff or improving your systems, and they aren’t happy.&lt;/p&gt;

&lt;p&gt;Since I started worrying about these anomalistic build times I’ve tried to learn what kind of things can cause them. I’ve read about ways to investigate them. Found some great tools, used them in our projects, built my own tools. Most of the stuff I’ve studied matches my main development environment: Visual Studio running on Windows, compiling C++ projects with MSVC.&lt;/p&gt;

&lt;p&gt;In this series I’d like to share what I’ve learned in the process, including some of those tools or how I’ve used them. Finally, I also want to talk about a way to visualize MSBuild’s build process using Google Chrome’s trace viewer and how it helped me. Have a look at a teaser:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-0/teaser-msbuild-flame-graph.png&quot; alt=&quot;MSBuild flame graph as shown by Google Chrome's trace viewer&quot; title=&quot;Teaser of the MSBuild-to-flame-graph tool&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To make this tool, I was inspired by &lt;a href=&quot;https://twitter.com/aras_p&quot;&gt;@aras_p&lt;/a&gt; from &lt;a href=&quot;https://aras-p.info/blog/2019/01/16/time-trace-timeline-flame-chart-profiler-for-Clang/&quot; target=&quot;_blank&quot;&gt;this blog post&lt;/a&gt;.&lt;br /&gt;
Thank you, Aras!&lt;/p&gt;

&lt;h2 id=&quot;disclaimer&quot;&gt;Disclaimer&lt;/h2&gt;

&lt;p&gt;Unfortunately, this isn’t a series about &lt;em&gt;how to speed up your compile times&lt;/em&gt;, that’s a series on its own. Instead, I want to share what I’ve learned while &lt;em&gt;investigating slow compile times&lt;/em&gt;: how MSBuild deals with solutions and projects, how to configure Visual Studio to add extra data or how some MSVC compiler flags can give you a heads up on your development cycle.&lt;/p&gt;

&lt;p&gt;You know, the first step when optimizing something is to get some metrics we can compare with, or else we couldn’t know whether it improved. In our case, one question that needs an answer is: &lt;em&gt;how long do the different steps in our build process take?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But first, try to give an estimate to this:&lt;/p&gt;

&lt;p class=&quot;notice--primary&quot;&gt;How much time &lt;strong&gt;you think&lt;/strong&gt; you waste waiting for your project to build, each day?&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="C++" /><category term="CSharp" /><category term="Visual Studio" /><category term="MSBuild" /><category term="Profiling" /><summary type="html">Why should we care?</summary></entry><entry><title type="html">Useful tools to investigate C++ compile times</title><link href="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-1/" rel="alternate" type="text/html" title="Useful tools to investigate C++ compile times" /><published>2020-03-25T00:00:00+00:00</published><updated>2020-03-25T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-1</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/investigating-cpp-compile-times-1/">&lt;p&gt;People build the projects they work on several times a day. More often than not, we perform the minimal build cycle: modify some code in a single file, save it and build. Other, sometimes painful, times we have to go through the full build cycle: rebuilding the whole project.&lt;/p&gt;

&lt;p&gt;These cycles take some time and what happens under the hood is totally dependent on your development environment and project.&lt;/p&gt;

&lt;p&gt;It took me a while to start worrying about these cycles and whether they were long or not. You know why it started? With rising anxiety and a feeling that I wasn’t as productive.&lt;/p&gt;

&lt;p&gt;These slow build times come with some costs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;People aren’t happy to stare at progress bar, so they may as well procrastinate and lose focus.&lt;/li&gt;
  &lt;li&gt;The time they waste waiting is time they aren’t improving your product, either adding new features or iterating.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, a while ago I set myself on a journey to identify what was causing them. And just so we are on the same page: my main development environment was Visual Studio 2015 running on Windows, building C++ projects with MSVC.&lt;/p&gt;

&lt;p&gt;This was (more or less!) the process to answer: &lt;strong&gt;how long does it take to build?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Disclaimer: I’ll be illustrating the process with my (unreleased) GameBoy emulator side-project. It’s a small project (we won’t see huge numbers) but it’s not a synthetic test (it mainly consists of C++ but uses C# and C++/CLI for a &lt;a href=&quot;https://metanokid.github.io/coding-scars/log-window-0/&quot;&gt;log window&lt;/a&gt;). This post will only cover how to get some build times, we’ll see examples of how to improve them in a later entry in the series.&lt;/p&gt;

&lt;h1 id=&quot;visual-studio-options&quot;&gt;Visual Studio options&lt;/h1&gt;

&lt;p&gt;Okay, so we build our project and have just an intuition of how long it takes. But we need some numbers! Just the big picture, nothing too detailed. All I had was Visual Studio’s output panel, and it just said:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;1&amp;gt;------ Rebuild All started: Project: LogWindowUI, Configuration: Debug x64 ------
1&amp;gt;  [...]
2&amp;gt;------ Rebuild All started: Project: LogWindowBridge, Configuration: Debug x64 ------
2&amp;gt;  [...]
3&amp;gt;------ Rebuild All started: Project: LogLibrary, Configuration: Debug x64 ------
3&amp;gt;  [...]
4&amp;gt;------ Rebuild All started: Project: GameBoy, Configuration: Debug x64 ------
4&amp;gt;  [...]
5&amp;gt;------ Rebuild All started: Project: MainWindows, Configuration: Debug x64 ------
5&amp;gt;  [...]
6&amp;gt;------ Rebuild All started: Project: Test, Configuration: Debug x64 ------
6&amp;gt;  [...]
========== Rebuild All: 6 succeeded, 0 failed, 0 skipped ==========&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I could take a stopwatch and start it as soon as I hit the build button, but not much more.&lt;/p&gt;

&lt;p&gt;After checking Visual Studio’s documentation and Stack Overflow questions on this matter, I ended up &lt;a href=&quot;https://docs.microsoft.com/visualstudio/ide/reference/options-dialog-box-projects-and-solutions-build-and-run&quot; target=&quot;_blank&quot;&gt;on this Microsoft Docs site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s explore some options.&lt;/p&gt;

&lt;h2 id=&quot;build-and-run&quot;&gt;Build and Run&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-1/visual-studio-options-build-and-run.png&quot; alt=&quot;Visual Studio's Build and Run options page&quot; title=&quot;Build and Run options page&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This page has several useful options, and we’ll come back to it later on, but let’s just take a look at &lt;em&gt;MSBuild project build output verbosity&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If we increase it from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Minimal&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Normal&lt;/code&gt;, we get this output:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;1&amp;gt;------ Rebuild All started: Project: LogWindowUI, Configuration: Debug x64 ------
1&amp;gt;Build started DD/MM/YYYY HH:MM:SS.
1&amp;gt;  [...]
1&amp;gt;Build succeeded.
1&amp;gt;
1&amp;gt;Time Elapsed 00:00:02.47
[...]
6&amp;gt;------ Rebuild All started: Project: Test, Configuration: Debug x64 ------
6&amp;gt;Build started DD/MM/YYYY HH:MM:SS.
6&amp;gt;  [...]
6&amp;gt;ClCompile:
6&amp;gt;  Main.cpp
6&amp;gt;  [...]
6&amp;gt;Link:
6&amp;gt;  [...]
6&amp;gt;Build succeeded.
6&amp;gt;
6&amp;gt;Time Elapsed 00:01:36.92
========== Rebuild All: 6 succeeded, 0 failed, 0 skipped ==========&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Great! We now have some data to work with! There are three interesting additions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Build started DD/MM/YYYY HH:MM:SS&lt;/code&gt;: the real output doesn’t show those letters, but actual numbers. We now know when this project started building.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Time Elapsed HH:MM:SS.ms&lt;/code&gt;: we now know how long it took to build this project.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClCompile&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Link&lt;/code&gt; and other new sections: they are what MSBuild calls &lt;em&gt;targets&lt;/em&gt;. We’ll come back to them in depth later on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we increase the previous option from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Normal&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Detailed&lt;/code&gt; the output will be more verbose, it will include more info on those &lt;em&gt;targets&lt;/em&gt; and also add &lt;em&gt;tasks&lt;/em&gt; to the log. All this data will prove extremely useful in the future, but they don’t add extra information on how long it takes to build. Even worse: the build itself gets slower as you increase this log level.&lt;/p&gt;

&lt;h2 id=&quot;vc-project-settings&quot;&gt;VC++ Project Settings&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-1/visual-studio-options-vcpp-project-settings.png&quot; alt=&quot;Visual Studio's VC++ Project Settings options page&quot; title=&quot;VC++ Project Settings option page&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This page also has a handful of useful options, but the most important one for us is &lt;em&gt;Build Timing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When we enable it and build our project, we get something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;[...]
6&amp;gt;------ Rebuild All started: Project: Test, Configuration: Debug x64 ------
6&amp;gt;Build started 25/03/2020 11:03:11.
6&amp;gt;  [...]
6&amp;gt;Project Performance Summary:
6&amp;gt;    96955 ms  F:\Development\GameBoyEmulator\Projects\Test\Test.vcxproj   1 calls
6&amp;gt;              96955 ms  Rebuild                                    1 calls
6&amp;gt;
6&amp;gt;Target Performance Summary:
6&amp;gt;        0 ms  AfterRebuild                               1 calls
6&amp;gt;       [...]
6&amp;gt;       41 ms  WarnCompileDuplicatedFilename              1 calls
6&amp;gt;      182 ms  CoreCppClean                               1 calls
6&amp;gt;      489 ms  SetCABuildNativeEnvironmentVariables       1 calls
6&amp;gt;     2332 ms  Link                                       1 calls
6&amp;gt;    93807 ms  ClCompile                                  1 calls
6&amp;gt;
6&amp;gt;Build succeeded.
6&amp;gt;
6&amp;gt;Time Elapsed 00:01:36.92
========== Rebuild All: 6 succeeded, 0 failed, 0 skipped ==========&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we’re talking! This output includes the time spent on each &lt;em&gt;target&lt;/em&gt; as reported by MSBuild (we still don’t know what’s a &lt;em&gt;target&lt;/em&gt;!), so we know where it’s getting slow. Are C++ file compilations slow? Or maybe link times are too high?&lt;/p&gt;

&lt;p&gt;By the way, this option and the one from the previous point aren’t related to each other: you can leave the former as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Minimal&lt;/code&gt; and enable the latter.&lt;/p&gt;

&lt;p&gt;So far, so good! What should we do with this, then? Should we try to parse this output and build a timeline already? Let’s continue looking for tools first.&lt;/p&gt;

&lt;h1 id=&quot;visual-studio-extensions&quot;&gt;Visual Studio extensions&lt;/h1&gt;

&lt;p&gt;A lot of the times you want some tool, chances are someone already built it. And, in this Visual Studio ecosystem we’re bound to, we should take a look at Extensions.&lt;/p&gt;

&lt;p&gt;Let me discuss a couple of the ones I found more suitable for my needs.&lt;/p&gt;

&lt;h2 id=&quot;build-monitor&quot;&gt;Build Monitor&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=danielperssson.BuildMonitor&quot; target=&quot;_blank&quot;&gt;Build Monitor&lt;/a&gt; is an interesting extension that supports, at the time of writing, up to Visual Studio 2015.&lt;/p&gt;

&lt;p&gt;Turns out, Visual Studio Extensions’ SDK lets you get notified of some MSBuild key events: when did the build start? when did a project finish? And that’s what this extension does. Build your solution and you’ll get this kind of output:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Solution loaded:    GameBoyEmulator
------------------------------------------------------------
 - 00h 00m 05s 298ms  -- LogWindowUI --
 - 00h 00m 03s 594ms  -- LogWindowBridge --
 - 00h 00m 01s 555ms  -- LogLibrary --
 - 00h 00m 06s 393ms  -- GameBoy --
 - 00h 00m 04s 852ms  -- MainWindows --
 - 00h 01m 38s 037ms  -- Test --
[1] Time Elapsed: 00h 01m 55s 300ms     Session build time: 00h 01m 55s 300ms&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While Visual Studio is open, it will keep track of the &lt;em&gt;session&lt;/em&gt;, adding up each compilation you do. What if you close Visual Studio? The &lt;em&gt;session&lt;/em&gt; is gone, but the coolest thing is that sessions are persisted to a JSON file! This way, you can always come back to them.&lt;/p&gt;

&lt;p&gt;This is good enough to compare two builds together!&lt;/p&gt;

&lt;h3 id=&quot;tool-idea&quot;&gt;Tool idea&lt;/h3&gt;

&lt;p&gt;Have all programmers (or everyone using Visual Studio!) in your team install this extension. Build a script that collects each JSON file at the end of the day, sends it to a server and clears the local one. Later on, aggregate all files together, tag data as necessary and you have the time your team is wasting by building the project (including how often each project is built)! If you plot it, you can even see some trends over time or spikes when a big code change happens.&lt;/p&gt;

&lt;p&gt;This is the &lt;em&gt;real time&lt;/em&gt; people waste, not how long your build server takes to make a build.&lt;/p&gt;

&lt;p&gt;Be careful, tho! The results may be daunting at first (i.e. too much time wasted)!&lt;/p&gt;

&lt;h2 id=&quot;parallel-builds-monitor&quot;&gt;Parallel Builds Monitor&lt;/h2&gt;

&lt;p&gt;If you liked the previous one but prefer a more graphical approach, then take a look at &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ivson4.ParallelBuildsMonitor-18691&quot; target=&quot;_blank&quot;&gt;Paralel Builds Monitor&lt;/a&gt;. It’s got better version support, up to Visual Studio 2019 (at the time of writing).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-1/parallel-builds-monitor.png&quot; alt=&quot;Parallel Builds Monitor&quot; title=&quot;Parallel Builds Monitor extension&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Although this extension can also export build data to a CSV file, it’s the Gantt chart that I like the most. Not only it tells you which projects are building in parallel (you may think you removed some dependency but didn’t!), it lets you quickly see how long did each project take to build. Absolutely recommended!&lt;/p&gt;

&lt;p&gt;This graph can be docked like another panel, so be careful if you’re an anxious person: seeing how much time is gone on each build may be unwise for you!&lt;/p&gt;

&lt;h1 id=&quot;msvc-compiler-flags&quot;&gt;MSVC compiler flags&lt;/h1&gt;

&lt;p&gt;Nice, so we’ve got some big numbers and we know which projects take longer to build. But we still don’t know where time is spent! Fortunately, MSVC has some compiler options that can help us investigate further:&lt;/p&gt;

&lt;h2 id=&quot;bt&quot;&gt;/Bt+&lt;/h2&gt;

&lt;p&gt;This flag applies to the compiler and produces this sample output when turned on:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;1&amp;gt;  File.cpp
1&amp;gt;  time(Z:\path\to\compiler\c1xx.dll)=0.39427s &amp;lt; 1617765075910 - 1617766036302 &amp;gt; BB [Z:\path\to\File.cpp]
1&amp;gt;  time(Z:\path\to\compiler\c2.dll)=0.06475s &amp;lt; 1617766053824 - 1617766211553 &amp;gt; BB [Z:\path\to\File.cpp]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This shows the time spent on the front-end (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c1xx.dll&lt;/code&gt; as we’re compiling C++ code, it would be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c1.dll&lt;/code&gt; when compiling C code) and on the back-end (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c2.dll&lt;/code&gt;). It’s extremely useful to narrow the long times down.&lt;/p&gt;

&lt;p&gt;You can find more info on the &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/vc-tip-get-detailed-build-throughput-diagnostics-using-msbuild-compiler-and-linker/&quot; target=&quot;_blank&quot;&gt;official C++ devblogs&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;time&quot;&gt;/time+&lt;/h2&gt;

&lt;p&gt;This one applies to the linker and gives this kind of output in a typical Debug build:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;5&amp;gt;  Linker: Pass 1: Interval #1, time = 0.78976s [Z:\path\to\program.exe]
5&amp;gt;  Linker:   Wait PDB close Total time = 0.32035s PB: 7331840 [Z:\path\to\program.exe]
5&amp;gt;  Linker: Pass 2: Interval #2, time = 0.48362s [Z:\path\to\program.exe]
5&amp;gt;  Linker: Final Total time = 1.27344s &amp;lt; 1618429762951 - 1618432864884 &amp;gt; PB: 7331840 [Z:\path\to\program.exe]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While you’ll get this info in a typical Release build:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll)   LTCG Load Main.obj: Total time = 0.04933s PB: 35180544 [Z:\path\to\program.exe]
5&amp;gt;  [...]
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll)   OptRef Total time = 0.00091s PB: 40161280 [Z:\path\to\program.exe]
5&amp;gt;  Generating code
5&amp;gt;  [...]
5&amp;gt;  Finished generating code
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll)   LTCG CodeGen Total time = 2.58961s PB: 57692160 [Z:\path\to\program.exe]
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll)   OptRef Total time = 0.00077s PB: 60547072 [Z:\path\to\program.exe]
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll)   OptIcf Total time = 0.00857s PB: 60551168 [Z:\path\to\program.exe]
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll) Pass 1: Interval #1, time = 3.56095s [Z:\path\to\program.exe]
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll)   Wait PDB close Total time = 0.14563s PB: 59539456 [Z:\path\to\program.exe]
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll) Pass 2: Interval #2, time = 0.23024s [Z:\path\to\program.exe]
5&amp;gt;  Linker: (Z:\path\to\compiler\c2.dll) Final Total time = 3.79130s &amp;lt; 1618638531573 - 1618647766698 &amp;gt; PB: 59539456 [Z:\path\to\program.exe]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Remember: by default Release configurations have &lt;a href=&quot;https://docs.microsoft.com/cpp/build/reference/ltcg-link-time-code-generation&quot; target=&quot;_blank&quot;&gt;Link Time Code Generation&lt;/a&gt; turned on to optimize further!&lt;/p&gt;

&lt;p&gt;You can also find &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/vc-tip-get-detailed-build-throughput-diagnostics-using-msbuild-compiler-and-linker/&quot; target=&quot;_blank&quot;&gt;more info here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;verbose&quot;&gt;/verbose&lt;/h2&gt;

&lt;p&gt;Although &lt;a href=&quot;https://docs.microsoft.com/cpp/build/reference/verbose-print-progress-messages&quot; target=&quot;_blank&quot;&gt;this flag&lt;/a&gt; doesn’t give you elapsed times, it’s also very useful if you want to investigate why link times are slow. I haven’t had much luck with it, but it’s interesting to see the amount of data the linker processes.&lt;/p&gt;

&lt;h2 id=&quot;d2cgsummary&quot;&gt;/d2cgsummary&lt;/h2&gt;

&lt;p&gt;This flag enables a cool behavior on the compiler’s back-end (hence the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d2&lt;/code&gt;) from Visual Studio 2015 onwards. I learned about this flag &lt;a href=&quot;https://aras-p.info/blog/2017/10/23/Best-unknown-MSVC-flag-d2cgsummary/&quot; target=&quot;_blank&quot;&gt;thanks to Aras&lt;/a&gt;, and I invite you to check his blog post for the full explanation!&lt;/p&gt;

&lt;p&gt;The key takeaway is that you get a summary of the code generation which includes anomalistic compile times and points you to the functions you should investigate!&lt;/p&gt;

&lt;p&gt;Although the slow build times I have investigated weren’t related to code generation, this flag is extremely useful!&lt;/p&gt;

&lt;h2 id=&quot;d1reporttime&quot;&gt;/d1reportTime&lt;/h2&gt;

&lt;p&gt;Again, I learned about this flag &lt;a href=&quot;https://aras-p.info/blog/2019/01/21/Another-cool-MSVC-flag-d1reportTime/&quot; target=&quot;_blank&quot;&gt;thanks to Aras&lt;/a&gt;, so please check his post for all of the info. This one applies to the compiler’s front-end (hence the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d1&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The bad thing about this flag is the huge amount of data it gives… and the cool thing is the huge amount of data it gives! You get, separately, the time spent when including files (hierarchically!), the one declaring classes and the same for functions. It also has a summary on each section with the top sorted culprits so you can find useful data more easily.&lt;/p&gt;

&lt;p&gt;If only we could visualize its output in a more graphical way…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/investigating-cpp-compile-times-1/teaser-d1reporttime-flag.png&quot; alt=&quot;/d1reportTime as shown by Google Chrome's trace viewer&quot; title=&quot;/d1reportTime as a flame graph&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is a teaser of the next post in the series!&lt;/p&gt;

&lt;p&gt;It’s a pity this flag is only available on Visual Studio 2017 onwards, because at the time I started investigating build times we were bound to VS2015.&lt;/p&gt;

&lt;h1 id=&quot;external-tools&quot;&gt;External tools&lt;/h1&gt;

&lt;p&gt;Now that we know how to get high level and low level build times, we should check some other tools to complement this data or help us diagnose why they’re happening.&lt;/p&gt;

&lt;p&gt;So far we’ve been talking about C++ development, and that means talking about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include&lt;/code&gt; clauses. We’ve also mentioned MSVC compiler execution consists of two phases:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Front-end: reads code files, parses them, executes preprocessor directives (i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include&lt;/code&gt; clauses) and applies semantic analysis.&lt;/li&gt;
  &lt;li&gt;Back-end: takes front-end’s output and performs code generation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you have large files and a lot of dependencies via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include&lt;/code&gt;, you’re bound to have long front-end execution times. When that’s the case, it’s useful to see those connections.&lt;/p&gt;

&lt;h2 id=&quot;doxygen&quot;&gt;doxygen&lt;/h2&gt;

&lt;p&gt;Yes, the one that helps you document your code. &lt;a href=&quot;http://www.doxygen.nl/&quot; target=&quot;_blank&quot;&gt;doxygen&lt;/a&gt; comes with a handful of tools, and one of them is building &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dot&lt;/code&gt; graphs.&lt;/p&gt;

&lt;p&gt;This example is extracted from &lt;a href=&quot;http://www.doxygen.nl/manual/examples/diagrams/html/diagrams__e_8h.html&quot; target=&quot;_blank&quot;&gt;doxygen’s docs&lt;/a&gt;, but trust me when I tell you it can handle huge dependency graphs:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.doxygen.nl/manual/examples/diagrams/html/diagrams__e_8h__incl.png&quot; alt=&quot;doxygen's include dependency graph&quot; title=&quot;doxygen include dependency graph&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The cool thing about these graphs is they’re interactive when you use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;html&lt;/code&gt; version (check previous link) and you can navigate at will. There’s even an option to configure the maximum inclusion depth in a single graph, so it has you covered!&lt;/p&gt;

&lt;h2 id=&quot;header-hero&quot;&gt;Header Hero&lt;/h2&gt;

&lt;p&gt;A long while ago I found &lt;a href=&quot;http://bitsquid.blogspot.com/2011/10/caring-by-sharing-header-hero.html&quot; target=&quot;_blank&quot;&gt;this blog post&lt;/a&gt; (which also gives very useful techniques to reduce your file dependencies!) and had a try. But it wasn’t until I read &lt;a href=&quot;https://twitter.com/aras_p&quot; target=&quot;_blank&quot;&gt;@aras_p&lt;/a&gt; in &lt;a href=&quot;https://aras-p.info/blog/2018/01/17/Header-Hero-Improvements/&quot; target=&quot;_blank&quot;&gt;this other blog post&lt;/a&gt; that I put it to good use.&lt;/p&gt;

&lt;p&gt;This tool has proven very useful, although it can take some trial and error to get the data you’re looking for when your project is very complex. I highly recommend you check Aras’ additions to the tool as well!&lt;/p&gt;

&lt;p&gt;When you get it working, take one of the biggest contributors or hubs, click on it and start exploring which files include it. Should they? Can you refactor your code so they don’t (i.e. forward declarations, remove nested classes or enums)?&lt;/p&gt;

&lt;h2 id=&quot;visual-studio-code-map&quot;&gt;Visual Studio Code Map&lt;/h2&gt;

&lt;p&gt;Unfortunately this tool is only available in a Visual Studio Enterprise installation, so I haven’t tested it myself (although it looks promising!).&lt;/p&gt;

&lt;p&gt;From what I see in the &lt;a href=&quot;https://docs.microsoft.com/visualstudio/modeling/map-dependencies-across-your-solutions&quot; target=&quot;_blank&quot;&gt;official documentation&lt;/a&gt; it produces complex graphs with several layers of data, but I guess some of that complexity may be configurable.&lt;/p&gt;

&lt;p&gt;The great thing about finding this tool was learning there’s a &lt;a href=&quot;https://docs.microsoft.com/visualstudio/modeling/directed-graph-markup-language-dgml-reference&quot; target=&quot;_blank&quot;&gt;graph format&lt;/a&gt; you can use for your own tools, and Visual Studio will be the viewer! You may use it for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#include&lt;/code&gt; clauses, asset dependencies or whatever fits in a directed graph!&lt;/p&gt;

&lt;h2 id=&quot;other-tools-with-dependency-graphs&quot;&gt;Other tools with dependency graphs&lt;/h2&gt;

&lt;p&gt;I also found some other Visual Studio extensions that give you inclusion dependency graphs like &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=Wumpf.IncludeToolbox&quot; target=&quot;_blank&quot;&gt;Include Toolbox&lt;/a&gt; (VS2017+) or &lt;a href=&quot;https://www.wholetomato.com/&quot; target=&quot;_blank&quot;&gt;Visual Assist&lt;/a&gt; (has a trial version).&lt;/p&gt;

&lt;p&gt;I’m sure there are a lot more!&lt;/p&gt;

&lt;h2 id=&quot;msbuild-structured-log-viewer&quot;&gt;MSBuild Structured Log Viewer&lt;/h2&gt;

&lt;p&gt;More recently, &lt;a href=&quot;https://twitter.com/KirillOsenkov&quot; target=&quot;_blank&quot;&gt;Kirill Osenkov&lt;/a&gt; pointed me to &lt;a href=&quot;https://msbuildlog.com/&quot; target=&quot;_blank&quot;&gt;MSBuild Structured Log Viewer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://msbuildlog.com/&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://msbuildlog.com/Screenshot1.png&quot; alt=&quot;MSBuild Structured Log Viewer&quot; title=&quot;MSBuild Structured Log Viewer&quot; class=&quot;align-center&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MSBuild 15.3 onwards lets you dump the full log it produces into a binary file you can read with that viewer. This includes project-target-task hierarchies, clicking on a target to see its definition in code and a great search tool. You can even &lt;em&gt;replay a build&lt;/em&gt; by feeding that same binary file to MSBuild in case you want to do something with it!&lt;/p&gt;

&lt;p&gt;I encourage you to give it a try! This tool shares one of the principles with the one we’ll talk about in the next post in the series, so it feels very familiar to me!&lt;/p&gt;

&lt;h2 id=&quot;c-build-insights&quot;&gt;C++ Build Insights&lt;/h2&gt;

&lt;p&gt;This one is even more recent, available from Visual Studio 2019 according to &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/introducing-c-build-insights/&quot; target=&quot;_blank&quot;&gt;Kevin’s blog post&lt;/a&gt; on the official C++ developers blog.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://devblogs.microsoft.com/cppblog/wp-content/uploads/sites/9/2019/11/word-image.gif&quot; alt=&quot;C++ Build Insights&quot; title=&quot;C++ Build Insights in WPA&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To put it simply, the new versions of MSVC compiler and linker emit &lt;a href=&quot;https://docs.microsoft.com/windows/win32/etw/event-tracing-portal&quot; target=&quot;_blank&quot;&gt;ETW events&lt;/a&gt; and they’ve added specially tailored panels to the &lt;a href=&quot;https://docs.microsoft.com/windows-hardware/test/wpt/windows-performance-analyzer&quot; target=&quot;_blank&quot;&gt;WPA&lt;/a&gt; so you can explore them. This means you’ll get exact timestamps, which is awesome when you want to investigate!&lt;/p&gt;

&lt;p&gt;And even more, &lt;a href=&quot;https://devblogs.microsoft.com/cppblog/analyze-your-builds-programmatically-with-the-c-build-insights-sdk/&quot; target=&quot;_blank&quot;&gt;Kevin shared this post&lt;/a&gt; not even a month ago with the release of an SDK to help you build your own tools on top of that info! This looks like the tool I was looking for, so thank you for the release!&lt;/p&gt;

&lt;p&gt;At the time of writing, you need to register to the Windows Insider Program to get the latest version, but it’s a quick process. Have a try and build great tools with it!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;After a couple of years investigating these build times it’s very possible I forgot about some tool or compiler flag, but this was more or less my process.&lt;/p&gt;

&lt;p&gt;We’ve mentioned MSBuild several times. We talked about &lt;em&gt;targets&lt;/em&gt; and &lt;em&gt;tasks&lt;/em&gt;. Further investigation led me to building my own tool so we can get a flame graph out of MSBuild! Visualizing data in a graphical may be key! That will be the next post in the series.&lt;/p&gt;

&lt;p&gt;Thank you for reading, hope some of these tools help you!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="C++" /><category term="CSharp" /><category term="Visual Studio" /><category term="MSBuild" /><category term="Profiling" /><category term="MSVC" /><category term="Flag" /><summary type="html">Let's talk about some of the tools I found and how I used them</summary></entry><entry><title type="html">Log window from scratch: C++ to C# interoperability</title><link href="https://metanokid.github.io/coding-scars/log-window-5/" rel="alternate" type="text/html" title="Log window from scratch: C++ to C# interoperability" /><published>2018-06-27T00:00:00+00:00</published><updated>2018-06-27T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/log-window-5</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/log-window-5/">&lt;p&gt;Hello and welcome to the last entry in the series!&lt;/p&gt;

&lt;p&gt;So far we’ve gone through the process of building a WPF live log window we could use from other C# projects. We made it a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt; and used it from a &lt;em&gt;host program&lt;/em&gt; also written in C#.&lt;/p&gt;

&lt;p&gt;This time, we’ll learn how we can have a C++ project use it. Yeah, that’s right: we’ll be calling C# from C++!&lt;/p&gt;

&lt;p&gt;Let’s do it!&lt;/p&gt;

&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;Before we dive into creating projects, configurations and code, let’s have a look into what we’ll need.&lt;/p&gt;

&lt;p&gt;First of all, our WPF log window is C# code. If we were to categorize it by how memory is dealt with, we’d call it &lt;em&gt;managed&lt;/em&gt;. This is because we create memory via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt; and the &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/&quot; target=&quot;_blank&quot;&gt;Garbage Collector&lt;/a&gt; will know when to &lt;em&gt;free&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;Second, our new &lt;em&gt;host program&lt;/em&gt; will be C++ code. However, because there’s no Garbage Collector of any sort, we can call it &lt;em&gt;unmanaged&lt;/em&gt;. We can also call it &lt;em&gt;native code&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So, you could say: &lt;em&gt;how can we invoke C# code from C++ code?&lt;/em&gt; The short answer is &lt;em&gt;you can’t, directly&lt;/em&gt;. Fortunately for us, there’s a long answer!&lt;/p&gt;

&lt;h2 id=&quot;ccli&quot;&gt;C++/CLI&lt;/h2&gt;

&lt;p&gt;There’s a language called &lt;a href=&quot;https://en.wikipedia.org/wiki/C%2B%2B/CLI&quot; target=&quot;_blank&quot;&gt;C++/CLI&lt;/a&gt; that we could basically say is C++ with new functionality to deal with .NET languages via &lt;a href=&quot;https://en.wikipedia.org/wiki/Common_Language_Infrastructure&quot; target=&quot;_blank&quot;&gt;Common Language Infrastructure&lt;/a&gt;. We could call this kind of code &lt;em&gt;mixed&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Knowing this, we could have C++/CLI code sitting in between of C++ and C#, like in this diagram:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-5/three-projects.png&quot; alt=&quot;Three projects&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With this picture in mind, these will be the steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create a C++ project with the typical &lt;em&gt;Hello, world!&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Create a C++/CLI project with a not-so-typical &lt;em&gt;Hello, mixed world!&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Connect these two so we can invoke the &lt;em&gt;mixed&lt;/em&gt; one from the &lt;em&gt;unmanaged&lt;/em&gt; one.&lt;/li&gt;
  &lt;li&gt;Connect the &lt;em&gt;mixed&lt;/em&gt; project with our &lt;em&gt;managed&lt;/em&gt; WPF one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;c-host-program&quot;&gt;C++ host program&lt;/h1&gt;

&lt;p&gt;Let’s start by adding a new C++ project to our solution: right-click it, then &lt;em&gt;Add -&amp;gt; New project…&lt;/em&gt; and choose &lt;em&gt;Win32 Console Application&lt;/em&gt; from the &lt;em&gt;Visual C++&lt;/em&gt; filter. Give it a descriptive name like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NativeHostProgram&lt;/code&gt;. From the wizard select &lt;em&gt;Empty project&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now, create the typical &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.cpp&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Set this project as the &lt;em&gt;startup project&lt;/em&gt; and run it. So far, so good. Next step?&lt;/p&gt;

&lt;h1 id=&quot;ccli-bridge-project&quot;&gt;C++/CLI bridge project&lt;/h1&gt;

&lt;p&gt;We’ve set our C++ project as the main one, so we can’t do the same for this C++/CLI project. Instead, we’ll use it from the &lt;em&gt;native&lt;/em&gt; one, and that means it must be a library.&lt;/p&gt;

&lt;p&gt;Again, right-click on the solution then &lt;em&gt;Add -&amp;gt; New project…&lt;/em&gt; but this time, under &lt;em&gt;Visual C++&lt;/em&gt; select the &lt;em&gt;CLR&lt;/em&gt; group. The only project type we’re given that matches our requirement is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt;, so let’s create that one. Give it a nice descriptive name, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By doing so, Visual Studio will also create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge.h&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge.cpp&lt;/code&gt; for us. I prefer deleting them to start from scratch once again.&lt;/p&gt;

&lt;p&gt;Let’s instead create a nice and simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge.h&lt;/code&gt; with this code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#pragma once
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;iostream&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;helloMixedWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, mixed world!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To be able to invoke this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;helloMixedWorld&lt;/code&gt; we must first connect the two projects together. But, how can we do that?&lt;/p&gt;

&lt;h2 id=&quot;referencing-bridge-from-native&quot;&gt;Referencing bridge from native&lt;/h2&gt;

&lt;p&gt;When we chose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt; while creating our C++/CLI project we were in fact creating a DLL, so we must follow the usual process for &lt;a href=&quot;https://docs.microsoft.com/en-us/cpp/build/linking-an-executable-to-a-dll&quot; target=&quot;_blank&quot;&gt;linking DLLs&lt;/a&gt;. This time, we’ll use the &lt;em&gt;Implicit Linking&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;Let’s change our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge.h&lt;/code&gt; file to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#pragma once
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#ifdef MIXED_MODE_DLL_EXPORT
#define MIXED_BRIDGE_API __declspec(dllexport)
#else
#define MIXED_BRIDGE_API __declspec(dllimport)
#endif
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MIXED_BRIDGE_API&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;helloMixedWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge.cpp&lt;/code&gt; file with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include &quot;Bridge.h&quot;
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;iostream&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MIXED_BRIDGE_API&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;helloMixedWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, mixed world!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Which will yield this error:&lt;/p&gt;

&lt;p class=&quot;notice--primary&quot;&gt;&lt;em&gt;Error: a function declared ‘dllimport’ may not be defined.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MIXED_MODE_DLL_EXPORT&lt;/code&gt; isn’t defined, which means we’re declaring the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;helloMixedWorld&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dllimport&lt;/code&gt;. However, DLL projects must use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dllexport&lt;/code&gt; for their functions so other projects use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dllimport&lt;/code&gt;. So, where can we define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MIXED_MODE_DLL_EXPORT&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Right-click the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge&lt;/code&gt; project and select Properties. Under &lt;em&gt;C/C++ &amp;gt; Preprocessor &amp;gt; Preprocessor definitions&lt;/em&gt; then add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MIXED_MODE_DLL_EXPORT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With this, the error has gone away!&lt;/p&gt;

&lt;p&gt;Now, compile the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge&lt;/code&gt; project alone. It should complete with no errors and will have created two files we’re interested in: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge.dll&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge.lib&lt;/code&gt;. These, alongside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge.h&lt;/code&gt; file are the three things we need to &lt;em&gt;implicitly link&lt;/em&gt; this DLL.&lt;/p&gt;

&lt;h3 id=&quot;implicit-linking&quot;&gt;Implicit Linking&lt;/h3&gt;

&lt;p&gt;We said we needed three things to be able to reference this DLL from our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NativeHostProgram&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Have access to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.h&lt;/code&gt; files with declarations.&lt;/li&gt;
  &lt;li&gt;Have access to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.lib&lt;/code&gt; file to perform the link.&lt;/li&gt;
  &lt;li&gt;Have access to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.dll&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, it’s pretty much working as a &lt;em&gt;static library&lt;/em&gt; although it is a DLL.&lt;/p&gt;

&lt;p&gt;Right-click &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NativeHostProgram&lt;/code&gt;, select Properties and perform these steps (we’re using paths from the default Visual Studio configuration):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Update &lt;em&gt;C/C++ &amp;gt; Additional Include Directories&lt;/em&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%(SolutionDir)LogWindowMixedBridge\;%(AdditionalIncludeDirectories)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Update &lt;em&gt;Linker &amp;gt; Additional Dependencies &amp;gt; Input&lt;/em&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge.lib;&lt;/code&gt; and all of the previous values.&lt;/li&gt;
  &lt;li&gt;Update &lt;em&gt;Linker &amp;gt; General &amp;gt; Additional Library Directories&lt;/em&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$(SolutionDir)\$(Configuration)\;%(AdditionalLibraryDirectories)&lt;/code&gt; for &lt;em&gt;Win32&lt;/em&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)&lt;/code&gt; for &lt;em&gt;x64&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last, but not least, we must tell the solution that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NativeHostProgram&lt;/code&gt; depends on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge&lt;/code&gt;. To do so, right-click the solution, select Properties and under &lt;em&gt;Project Dependencies&lt;/em&gt; select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NativeHostProgram&lt;/code&gt; and check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge&lt;/code&gt;. From now on, when we compile the solution it will first compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge&lt;/code&gt; and then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NativeHostProgram&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Well, we’ve linked everything so we can go back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.cpp&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NativeHostProgram&lt;/code&gt; and update it with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;Bridge.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;helloMixedWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Run the solution and you’ll have an impressive message in your console saying the &lt;em&gt;Hello, mixed world!&lt;/em&gt; message!&lt;/p&gt;

&lt;p&gt;Phew! It was intense! Well done :)&lt;/p&gt;

&lt;h1 id=&quot;connecting-ccli-to-c&quot;&gt;Connecting C++/CLI to C#&lt;/h1&gt;

&lt;p&gt;Nice! We know how to connect C++ with C++/CLI, but how about going from C++/CLI to C#? The answer is in fact pretty simple: reference it!&lt;/p&gt;

&lt;p&gt;To do so, expand our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowMixedBridge&lt;/code&gt; project, right-click References, select &lt;em&gt;Add Reference…&lt;/em&gt; and then check our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt; project (which, if you remember from previous entries, is our C# WPF project).&lt;/p&gt;

&lt;p&gt;Now we can update our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge.cpp&lt;/code&gt; file with this code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include &quot;Bridge.h&quot;
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MIXED_BRIDGE_API&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;helloMixedWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;LogWindowUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;LogWindowUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;DEBUG&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, WPF!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// required so we can see the window for a bit&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Threading&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Run it and you’ll get this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-5/hello-wpf-from-mixed.png&quot; alt=&quot;Hello WPF from mixed&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Impressive! It may look like no big deal, but we’ve shown our log window from a code that started at C++! Now, for the last bit!&lt;/p&gt;

&lt;h1 id=&quot;bridge-revisited&quot;&gt;Bridge revisited&lt;/h1&gt;

&lt;p&gt;Alright, we’re awesome because we communicated C++ with C#, but for now it’s just a function! Why don’t we design it a bit and make our C++ program configure the C# WPF window and log some stuff?&lt;/p&gt;

&lt;p&gt;Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; class, which belongs to C#, has methods to deal with the window like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Initialize&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConfigureSystems&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add&lt;/code&gt;. Wouldn’t it be awesome to have some kind of &lt;em&gt;wrapper&lt;/em&gt; in our C++/CLI project to call them from C++? We’re doing that now.&lt;/p&gt;

&lt;p&gt;Let’s modify our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge.h&lt;/code&gt; file with this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#pragma once
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#ifdef MIXED_MODE_DLL_EXPORT
#define MIXED_BRIDGE_API __declspec(dllexport)
#else
#define MIXED_BRIDGE_API __declspec(dllimport)
#endif
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;vector&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MIXED_BRIDGE_API&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configureSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Notice how we can export a whole class with the DLL, not just free functions. As you can see, its methods mostly map those at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt;. Why don’t we see some of the implementations?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;LogWindowUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;LogWindowUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nothing pretty fancy here, right? What about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configureSystems&lt;/code&gt;, for example?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configureSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Generic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tManagedStringList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;tManagedStringList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;systemsManaged&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcnew&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tManagedStringList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;systemsManaged&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcnew&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;LogWindowUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConfigureSytems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;systemsManaged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is what our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge&lt;/code&gt; is all about: translating stuff from C++ to C#. See how we’re converting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const char *&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;? Okay, but you may say: &lt;em&gt;what’s that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String ^&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcnew&lt;/code&gt;?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^&lt;/code&gt; symbol represents a pointer to managed memory, and that memory must be created somewhere. That’s where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcnew&lt;/code&gt; comes into play: creates memory handled by the Garbage Collector. We could say they are the managed counterparts of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;loggerui-as-a-singleton&quot;&gt;LoggerUI as a Singleton&lt;/h2&gt;

&lt;p&gt;By now you’ve already noticed we’re enforcing having a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; instance because it’s a Singleton. However, nothing prevents us from creating several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge&lt;/code&gt; instances! We could create two of them and then an assert would trigger because we’d be trying to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI::Initialize&lt;/code&gt; twice!&lt;/p&gt;

&lt;p&gt;We could fix it by ditching out the Singleton pattern at this level and having our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge&lt;/code&gt; &lt;em&gt;wrapper&lt;/em&gt; have a private &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; member. However, it’s a bit more convoluted than I wanted to dive into when I started this post so we’ll keep it out of scope.&lt;/p&gt;

&lt;p&gt;Long story short, it requires creating a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BridgePrivate&lt;/code&gt; class to be used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bridge&lt;/code&gt; (pretty much like the &lt;a href=&quot;https://en.cppreference.com/w/cpp/language/pimpl&quot; target=&quot;_blank&quot;&gt;PIMPL&lt;/a&gt;) with a member of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcroot&amp;lt;LoggerUI ^&amp;gt;&lt;/code&gt;. The reason is we can’t expose a C++/CLI class to C++ with pointers to managed memory, so we must hide it in the private class.&lt;/p&gt;

&lt;h1 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h1&gt;

&lt;p&gt;The only thing we’re missing is calling all this from C++! Let’s update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.cpp&lt;/code&gt; with this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c--&quot; data-lang=&quot;c++&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include &quot;Bridge.h&quot;
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;chrono&amp;gt;
#include &amp;lt;thread&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;DEBUG&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;#000000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bridge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configureSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;DEBUG&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello from native C++!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this_thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chrono&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And this is the result:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-5/hello-wpf-from-cpp.png&quot; alt=&quot;Hello WPF from native C++&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What if we configured more levels and more systems? What if we logged messages with random level and system? What if we recorded it into a GIF?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-5/live-log-window.gif&quot; alt=&quot;Live log window&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You’re now logging messages from C++ to a WPF window written in C#!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Wow, so that’s the end of the series! We’ve gone through the process of creating a WPF live log window which we can use from C# and C++ projects. We’ve started from nothing and got to the previous GIF showing the result, and what a result! :)&lt;/p&gt;

&lt;p&gt;The only thing that’s left is using it in other &lt;em&gt;real&lt;/em&gt; projects! What are you waiting for?&lt;/p&gt;

&lt;p&gt;Thanks a lot for reading!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="Log" /><category term="WPF" /><category term="CSharp" /><category term="C++" /><category term="C++/CLI" /><category term="Managed" /><category term="Unmanaged" /><category term="Mixed" /><summary type="html">Connect a native C++ project with our C# WPF log window</summary></entry><entry><title type="html">Log window from scratch: handy functionality and configuration (part 2)</title><link href="https://metanokid.github.io/coding-scars/log-window-4/" rel="alternate" type="text/html" title="Log window from scratch: handy functionality and configuration (part 2)" /><published>2018-06-19T00:00:00+00:00</published><updated>2018-06-19T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/log-window-4</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/log-window-4/">&lt;p&gt;In the previous post we went through some interesting functionalities for our log window but we were missing the, arguably, most important one.&lt;/p&gt;

&lt;p&gt;Should we start working on it? Oh yes, and you’ll love it.&lt;/p&gt;

&lt;h1 id=&quot;log-levels&quot;&gt;Log levels&lt;/h1&gt;

&lt;p&gt;This wouldn’t be a proper log window if we didn’t have log levels (&lt;em&gt;debug&lt;/em&gt;, &lt;em&gt;warning&lt;/em&gt;, &lt;em&gt;error&lt;/em&gt;) and colors for them!&lt;/p&gt;

&lt;p&gt;Again, we’ll let the &lt;em&gt;host program&lt;/em&gt; decide which log levels it uses, their names and even the colors. And yes, you’ve guessed right, we’ll do that in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; singleton.&lt;/p&gt;

&lt;p&gt;But before we start, what’s the relationship between different log levels? How about using the common one: each level represents an integer (higher means more severity). Like in this example:&lt;/p&gt;

&lt;p&gt;Imagine we had three log levels: &lt;em&gt;debug&lt;/em&gt;, &lt;em&gt;warning&lt;/em&gt; and &lt;em&gt;error&lt;/em&gt;. We could use &lt;em&gt;debug&lt;/em&gt; to log data or flow, &lt;em&gt;warning&lt;/em&gt; would let us know of non-blocking incompatibilities or to diagnose future issues and &lt;em&gt;error&lt;/em&gt; would flag stuff that must be fixed although we managed to continue executing the program. If we set our current log level to &lt;em&gt;warning&lt;/em&gt;, we would also see &lt;em&gt;error&lt;/em&gt; ones because their severity is higher.&lt;/p&gt;

&lt;p&gt;Oh, and for it to work we must remember to update our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; messages to have a log level as well!&lt;/p&gt;

&lt;h2 id=&quot;configuration-from-the-host&quot;&gt;Configuration from the host&lt;/h2&gt;

&lt;p&gt;We’ve decided each log level is modelled as a name and a color. The severity can be implicit based on the configuration: the first ones are less important. What about adding this to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginInvoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;delegate&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We could’ve created a new class or struct as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt; for each log level but we’ve used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tuple&amp;lt;string, string&amp;gt;&lt;/code&gt; instead to get to the point. The first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; is the name, the second one is the hexadecimal representation of the color.&lt;/p&gt;

&lt;p&gt;We could call it like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;DEBUG&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;s&quot;&gt;&quot;#000000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WARNING&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;#B8860B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ERROR&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;s&quot;&gt;&quot;#FF0000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, we’d have to create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.ConfigureLevels&lt;/code&gt;, but let’s create a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; before.&lt;/p&gt;

&lt;h2 id=&quot;viewmodel&quot;&gt;ViewModel&lt;/h2&gt;

&lt;p&gt;Similarly to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogSystem&lt;/code&gt; one we created in the previous post, let’s define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogLevel&lt;/code&gt; as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogLevel&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brush&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Severity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again, let’s have a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogLevels&lt;/code&gt; list in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt; to contain all of the levels. And we could populate it from this method:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LogLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Item1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Brush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BrushConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConvertFromString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Item2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Severity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You’ll understand why we’ve used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Brush&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Color&lt;/code&gt; in a moment.&lt;/p&gt;

&lt;p&gt;Cool! Now we’ve got all of the values in a list. What’s next?&lt;/p&gt;

&lt;h2 id=&quot;add-log-level-to-logentry&quot;&gt;Add log level to LogEntry&lt;/h2&gt;

&lt;p&gt;Right, until now all of our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; messages only had a timestamp, a system and the message itself. Now, we need to add the name of the log level it was logged with. I’ll let you go through this one, just add a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; property and we’re ready.&lt;/p&gt;

&lt;h2 id=&quot;layout-update&quot;&gt;Layout update&lt;/h2&gt;

&lt;p&gt;We’ve established the relationship between log levels. Following our example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;debug &amp;lt; warning &amp;lt; error&lt;/code&gt;. So, we only want to select the minimum level we’re showing and the ones over it should show as well. This looks like a radio button to me.&lt;/p&gt;

&lt;p&gt;The layout of our window would look like this with this addition:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/doodle-full-layout.png&quot; alt=&quot;Doodle with full layout&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So, once again, let’s skip some XML attributes and update the layout:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Window&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DockPanel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GroupBox&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GroupBox&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StackPanel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Systems&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Levels&quot;&lt;/span&gt;
                          &lt;span class=&quot;n&quot;&gt;ScrollViewer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HorizontalScrollBarVisibility&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Disabled&quot;&lt;/span&gt;
                          &lt;span class=&quot;n&quot;&gt;BorderThickness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemsPanel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemsPanelTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WrapPanel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Orientation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Horizontal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WrapPanel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemsPanelTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemsPanel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RadioButton&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Name}&quot;&lt;/span&gt;
                                         &lt;span class=&quot;n&quot;&gt;GroupName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LogLevels&quot;&lt;/span&gt;
                                         &lt;span class=&quot;n&quot;&gt;Foreground&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Color}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RadioButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StackPanel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GroupBox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LogEntryList&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DockPanel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foreground&lt;/code&gt; property expects a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Brush&lt;/code&gt; instead of a raw &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Color&lt;/code&gt;, so that’s the reason why we used one.&lt;/p&gt;

&lt;p&gt;Tweaking the sample messages a bit and taking a screenshots looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/log-levels-first-steps.png&quot; alt=&quot;Log levels' first steps&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, none of the elements is checked. We’ll work on that soon. But first, let’s add some colors to the messages!&lt;/p&gt;

&lt;h2 id=&quot;message-coloring&quot;&gt;Message coloring&lt;/h2&gt;

&lt;p&gt;Now that all of the messages have a log level themselves, we could style the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntryList&lt;/code&gt; so each row has a color matching the configuration. That way, we can skip adding a new column with the name of the log level.&lt;/p&gt;

&lt;p&gt;If all of our log levels and their colors were static resources we’d be defining them in XAML. Since we’re configuring it externally, we must create the styles programmatically.&lt;/p&gt;

&lt;p&gt;To do that, let’s update our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.ConfigureLevels&lt;/code&gt; like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// create log levels&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LogLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Severity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Item1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Brush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BrushConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConvertFromString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Item2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// style ListView based on the data from the log levels&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Style&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logListStyle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logListStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TargetType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListViewItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;DataTrigger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trigger&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DataTrigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Binding&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Binding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Level&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Setters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Setter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListViewItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForegroundProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;logListStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Triggers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;LogEntryList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemContainerStyle&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logListStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Style&lt;/code&gt;, as we can see, has the concept of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataTrigger&lt;/code&gt;. It takes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Binding&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Value&lt;/code&gt; to test against, and if it matches then the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Setters&lt;/code&gt; are applied. In our case just a text color, but we could use other styling. Finally, we assign the whole style to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ItemContainerStyle&lt;/code&gt;, which is the one applied to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListViewItem&lt;/code&gt; entries.&lt;/p&gt;

&lt;p&gt;This is the result:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/styled-log-messages.png&quot; alt=&quot;Styled log messages&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Looking nice, huh? However, there’s something missing, isn’t it?&lt;/p&gt;

&lt;h2 id=&quot;filtering&quot;&gt;Filtering&lt;/h2&gt;

&lt;p&gt;Alright, alright. We’re happy with the results but we still can’t do anything with these radio buttons! Let’s see what’s left.&lt;/p&gt;

&lt;p&gt;We said we’d be adopting the usual &lt;em&gt;each log level has a severity and we can show all of the logs with a higher severity level than the selected one&lt;/em&gt;. We’ve got as many radio buttons as log levels, and each one represents a severity (although we aren’t displaying the number itself).&lt;/p&gt;

&lt;p&gt;So, it looks like we only want one variable: the currently selected log level. But, how do we go from many radio buttons to a single value?&lt;/p&gt;

&lt;p&gt;First of all, let’s create a new variable in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CurrentLogLevelSeverity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, let’s update our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogLevel&lt;/code&gt; class to this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PropertyChangedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brush&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;Severity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_selected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Selected&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_selected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;m_selected&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;PropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Selected&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It looks pretty similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogSystem&lt;/code&gt;, doesn’t it?&lt;/p&gt;

&lt;p&gt;Now, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.ConfigureLevels&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// create log levels&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Severity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Item1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Brush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;BrushConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConvertFromString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;levels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Item2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnLevelSelectedChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;LogLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So, whenever the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogLevel&lt;/code&gt; changes (when the user interacts with the radio buttons) we’ll get notified. And what do we do then?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnLevelSelectedChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PropertyChangedEventArgs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Selected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;CurrentLogLevelSeverity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Severity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;FilteredLogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Refresh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Selected&lt;/code&gt; property will be modified for both the radio button that’s getting selected and the one that’s being deselected, we’re just interested in the former. We update the log level and ask the filter to be re-evaluated.&lt;/p&gt;

&lt;p&gt;But, we must add the log level to the filter or it won’t do anything different!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LogEntriesFilterPredicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// filter out systems&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// filter out levels&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogLevel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogLevels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Severity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CurrentLogLevelSeverity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Each message has the name of the log level it was logged with, and we have the severity we want to test against. So, we find out which &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogLevel&lt;/code&gt; matches the given name and only keep those messages with a matching or greater severity. Bonus points if you can optimize this to prevent looking for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogLevel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And that’s it! Let’s take some screenshots!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/debug-or-higher.png&quot; alt=&quot;Filter by level: debug or higher&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/warning-or-higher.png&quot; alt=&quot;Filter by level: warning or higher&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/error-or-higher.png&quot; alt=&quot;Filter by level: error or higher&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Not bad! But can we improve the layout so it looks better?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/final-sample-window.png&quot; alt=&quot;Final sample window&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What about adding more systems and more log levels from the host program? Don’t cheat, you can’t modify the WPF project!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-4/final-sample-window-extra-configuration.png&quot; alt=&quot;Final sample window with extra configuration&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, reader! You’ve got a configurable log window of your own! :)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Oh well, I guess that’s it! With this post and the previous one we’ve gone through some useful features: positioning, auto-scrolling, configuring log systems and log levels, filtering… Which other features you’d like to add? I encourage you to do it!&lt;/p&gt;

&lt;p&gt;I hope this series helps you create your own version of the log window and use it in the future on your side projects!&lt;/p&gt;

&lt;p&gt;In the next post we’ll see how we can have a C++ &lt;em&gt;host program&lt;/em&gt; that uses this log window.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="Log" /><category term="WPF" /><category term="CSharp" /><category term="MVVM" /><category term="Class Library" /><category term="Filter" /><category term="Log level" /><category term="Debug" /><category term="Warning" /><category term="Error" /><summary type="html">Final configuration with log levels, coloring and its filters</summary></entry><entry><title type="html">Log window from scratch: handy functionality and configuration (part 1)</title><link href="https://metanokid.github.io/coding-scars/log-window-3/" rel="alternate" type="text/html" title="Log window from scratch: handy functionality and configuration (part 1)" /><published>2018-06-17T00:00:00+00:00</published><updated>2018-06-17T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/log-window-3</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/log-window-3/">&lt;p&gt;Welcome to a new entry in the &lt;em&gt;Log window from scratch&lt;/em&gt; series, dear reader!&lt;/p&gt;

&lt;p&gt;In the previous entry we converted our WPF window into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt; and created a &lt;em&gt;host program&lt;/em&gt; that used it to display some sample messages. This time, we’ll expose some configuration to the &lt;em&gt;host program&lt;/em&gt; and add some new functionality to the window. This way we can support several projects and make it more useful.&lt;/p&gt;

&lt;p&gt;Ready? Set? Go!&lt;/p&gt;

&lt;h1 id=&quot;window-position-and-dimensions&quot;&gt;Window position and dimensions&lt;/h1&gt;

&lt;p&gt;Let’s start with a simple one: setting the position and size of our window.&lt;/p&gt;

&lt;p&gt;Imagine you are developing a game and it has a window where it gets rendered. You don’t want your log window to be created over it (or under it!), but side to side instead.&lt;/p&gt;

&lt;p&gt;We could add two new methods to our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetPosition&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetSize&lt;/code&gt;, or we could pass these parameters to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Initialize&lt;/code&gt; method and have them set from the start. For now, let’s pass them to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Initialize&lt;/code&gt; since we don’t plan on resizing it programatically after it’s shown.&lt;/p&gt;

&lt;p&gt;First, update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Initialize&lt;/code&gt; like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;LoggerUI already initialized&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So we can call it like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Of course, we’d need to update our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt;’s constructor to match the new parameter:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dimensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// application and window need their own thread, so we create it&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AutoResetEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;windowCreatedEvent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AutoResetEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// set window dimensions&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WindowStartupLocation&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WindowStartupLocation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Manual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dimensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Top&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dimensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Width&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dimensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Height&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dimensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// notify they are created before we block this thread&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;windowCreatedEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetApartmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApartmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// wait until the application and window are created&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;windowCreatedEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WaitOne&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The only addition has been the block where we set the dimensions.&lt;br /&gt;
And this is it! We can now position and size it however we want.&lt;/p&gt;

&lt;p&gt;Bonus idea: we could ask the window about these properties (which would be updated when resizing or moving the window) from the host program and persist its values so we could start from the last configuration when we launch the program again.&lt;/p&gt;

&lt;h1 id=&quot;auto-scroll-to-bottom&quot;&gt;Auto-scroll to bottom&lt;/h1&gt;

&lt;p&gt;This will be the first addition that will modify our window’s layout.&lt;/p&gt;

&lt;p&gt;If you were to use the window as it is now, you would notice the scroll isn’t moving unless you do it manually. This may be useful if you are reading some of the messages, but most of the time you may want it to scroll to the last message automatically.&lt;/p&gt;

&lt;p&gt;We’ll be adding a checkbox to our window that lets us activate or deactivate this functionality. This isn’t something the &lt;em&gt;host program&lt;/em&gt; can choose to have or not, but something that’s built-in. So our layout will be something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-3/doodle-built-in-configuration.png&quot; alt=&quot;Doodle layout built-in configuration and log messages&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;layout-update&quot;&gt;Layout update&lt;/h2&gt;

&lt;p&gt;Let’s start with the built-in block. This is the updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml&lt;/code&gt; file with some parts commented out for the sake of brevity:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Window&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;DockPanel&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;GroupBox&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;DockPanel.Dock=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Top&quot;&lt;/span&gt;
                  &lt;span class=&quot;na&quot;&gt;x:Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;BuiltInConfigurationGroup&quot;&lt;/span&gt;
                  &lt;span class=&quot;na&quot;&gt;VerticalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Top&quot;&lt;/span&gt;
                  &lt;span class=&quot;na&quot;&gt;BorderThickness=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;CheckBox&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x:Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;AutoScrollCheckBox&quot;&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;Content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Auto-scroll&quot;&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;HorizontalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Right&quot;&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;VerticalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Center&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/GroupBox&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;DockPanel.Dock=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Top&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- other properties --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/DockPanel&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Window&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we’ve wrapped everything into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DockPanel&lt;/code&gt; which allows us to resize the window and keep every control stretched as we want while keeping some parts fixed. This is how it looks:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-3/layout-with-auto-scroll.png&quot; alt=&quot;New layout with auto-scroll&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;auto-scroll-property&quot;&gt;Auto-scroll property&lt;/h2&gt;

&lt;p&gt;Now we have to connect that checkbox to some &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt;. We’ll update its XAML definition as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;CheckBox&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x:Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;AutoScrollCheckBox&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;IsChecked=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Path=IsAutoScrollEnabled}&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;Content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Auto-scroll&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;HorizontalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Right&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;VerticalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Center&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With that, we’ve tied a yet-to-be-created variable called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsAutoScrollEnabled&lt;/code&gt; to our checkbox. Let’s add it in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml.cs&lt;/code&gt; class:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_autoScrollEnabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IsAutoScrollEnabled&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_autoScrollEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_autoScrollEnabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;AddLogEntry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;INTERNAL&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Auto-scroll is now &quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_autoScrollEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you were to do this, it wouldn’t work because we’re trying to bind a variable from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataContext&lt;/code&gt; that’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; by default. To fix that we must do this in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml.cs&lt;/code&gt;’s constructor:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;DataContext&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now it will work as expected.&lt;/p&gt;

&lt;p&gt;For now, we’ve used our own log capability to show a message in the window whenever we modify the property. If we were to run it and click on the checkbox several times we’d get something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-3/auto-scroll-on-change-log.png&quot; alt=&quot;Auto-scroll on change log&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;scroll-to-bottom&quot;&gt;Scroll to bottom&lt;/h2&gt;

&lt;p&gt;By default, when a new item is added to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt; that contains our log messages no scroll is performed. We’d want to know when an item is added to the list so we can perform the scroll ourselves.&lt;/p&gt;

&lt;p&gt;Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; variable (which is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ObservableCollection&lt;/code&gt;) has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CollectionChanged&lt;/code&gt; event handler we can subscribe to. So, first of all let’s create a method in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml.cs&lt;/code&gt; to handle the scroll:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnLogEntriesChangedScrollToBottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NotifyCollectionChangedEventArgs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsAutoScrollEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VisualTreeHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetChildrenCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogEntryList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Decorator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;border&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VisualTreeHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogEntryList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Decorator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ScrollViewer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scrollViewer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ScrollViewer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VisualTreeHelper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;scrollViewer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ScrollToBottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Basically, we ask the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntryList&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt; for its children, get the scroll control for the list and ask it to go to the bottom. We can also check the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotifyCollectionChangedEventArgs&lt;/code&gt; to know whether it was triggered because an item was added or deleted, if we wanted to.&lt;/p&gt;

&lt;p&gt;Now, to tie it with our checkbox, add this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CollectionChanged&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnLogEntriesChangedScrollToBottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can now, also, refactor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsAutoScrollEnabled&lt;/code&gt; with just this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IsAutoScrollEnabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Congratulations, you’ve got an auto-scrolling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt;!&lt;/p&gt;

&lt;h1 id=&quot;per-system-filters&quot;&gt;Per system filters&lt;/h1&gt;

&lt;p&gt;So far the new features are great additions, but how about being able to filter messages by their system?&lt;/p&gt;

&lt;p&gt;Imagine you’re working on program and there’s some bug you’re tracking down related to the &lt;em&gt;net communication&lt;/em&gt;. Wouldn’t it be awesome to filter out everything else and only read the logs for that system? Something easy like clicking on different checkboxes?&lt;/p&gt;

&lt;p&gt;However, the goal of this log window is to be used in more than a single project and each one of them may have completely diferent systems. So, how do we do it?&lt;/p&gt;

&lt;h2 id=&quot;configuration-from-the-host&quot;&gt;Configuration from the host&lt;/h2&gt;

&lt;p&gt;Remember our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; entry point? We’re adding a new method to let the &lt;em&gt;host program&lt;/em&gt; tell us which systems it will be using so we can create as many checkboxes. This could be the outline:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureSytems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginInvoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;delegate&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Of course, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.ConfigureSystems&lt;/code&gt; doesn’t exist, so we must create it. But first, let’s think about what we need at the &lt;em&gt;Window&lt;/em&gt; level.&lt;/p&gt;

&lt;p&gt;We’re going to have a list of checkboxes, one for each system we’ve received and we want to know whether they are checked to filter the messages. Phew! Let’s digest all that.&lt;/p&gt;

&lt;h2 id=&quot;viewmodel&quot;&gt;ViewModel&lt;/h2&gt;

&lt;p&gt;We could have a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogSystem&lt;/code&gt; which contains the name of the system (as received from the host) as well as the state of the checkbox we’ll present to the user. Something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogSystem&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And this way, we can have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;LogSystem&amp;gt;&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ObservableCollection&amp;lt;LogSystem&amp;gt;&lt;/code&gt;) in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt; that contains all of the entries. By having that, we could have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.ConfigureSystems&lt;/code&gt; do this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ForEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LogSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogSystem&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;filtering&quot;&gt;Filtering&lt;/h2&gt;

&lt;p&gt;Remember &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt;? The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;LogEntry&amp;gt;&lt;/code&gt; where we store all of the log messages we receive? Well, we want to filter it now. To do that, we’ll create a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICollectionView&lt;/code&gt; from it.&lt;/p&gt;

&lt;p&gt;An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICollectionView&lt;/code&gt; lets us sort, filter or group data from a given collection via predicate. This predicate is a function that decides, for each element in the collection, whether it belongs to the filtered data.&lt;/p&gt;

&lt;p&gt;By the way, don’t let the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; part of the name fool you. This doesn’t have anything to do with visual representation, it’s just the way to call this kind of filtered collection.&lt;/p&gt;

&lt;p&gt;So, we’ve got to create it in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ICollectionView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FilteredLogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And initialize it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;FilteredLogEntries&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CollectionViewSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetDefaultView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FilteredLogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Filter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntriesFilterPredicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we take &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; and create a &lt;em&gt;view&lt;/em&gt; of the data. By the way, you may want to transfer the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CollectionChanged&lt;/code&gt; event to this one so we apply the scroll when this one changes and not the unfiltered one. Then we assign our filter, which looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LogEntriesFilterPredicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// filter out systems&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In other words, we keep any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; unless the matching &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogSystem&lt;/code&gt; is disabled.&lt;/p&gt;

&lt;p&gt;This implementation has an unexpected behavior at this point, but let’s continue and discover it later on.&lt;/p&gt;

&lt;h2 id=&quot;layout-update-1&quot;&gt;Layout update&lt;/h2&gt;

&lt;p&gt;We said we’d like to have as many checkboxes as systems so we could filter them to fit our needs. So, we need to add them somewhere. Maybe… to the bottom like this?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-3/doodle-per-system-filter-layout.png&quot; alt=&quot;Doodle layout with per-system filters&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For that, and again skipping some of the XML attributes, we have to update our layout to this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Window&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;DockPanel&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;GroupBox&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;CheckBox&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/GroupBox&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;GroupBox&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;DockPanel.Dock=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Bottom&quot;&lt;/span&gt;
                  &lt;span class=&quot;na&quot;&gt;VerticalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Top&quot;&lt;/span&gt;
                  &lt;span class=&quot;na&quot;&gt;BorderThickness=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Systems&quot;&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;ScrollViewer.HorizontalScrollBarVisibility=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Disabled&quot;&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;BorderThickness=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;ListView.ItemsPanel&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemsPanelTemplate&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;nt&quot;&gt;&amp;lt;WrapPanel&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Orientation=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Horizontal&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/WrapPanel&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemsPanelTemplate&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ListView.ItemsPanel&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;ListView.ItemTemplate&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;DataTemplate&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;nt&quot;&gt;&amp;lt;CheckBox&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Name}&quot;&lt;/span&gt;
                                  &lt;span class=&quot;na&quot;&gt;IsChecked=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Enabled}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/CheckBox&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/DataTemplate&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ListView.ItemTemplate&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/GroupBox&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x:Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LogEntryList&quot;&lt;/span&gt;
                  &lt;span class=&quot;na&quot;&gt;VerticalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Stretch&quot;&lt;/span&gt;
                  &lt;span class=&quot;na&quot;&gt;HorizontalAlignment=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Stretch&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/DockPanel&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Window&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And remember to set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ItemsSource&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Systems&lt;/code&gt; element!&lt;/p&gt;

&lt;p&gt;And this is how it would look like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-3/sample-system-bottom-row.png&quot; alt=&quot;Sample systems bottom row&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Impressive, isn’t it? Except it has a bug.&lt;/p&gt;

&lt;h3 id=&quot;testing-filter&quot;&gt;Testing filter&lt;/h3&gt;

&lt;p&gt;If you asked me, before even executing the log window, &lt;em&gt;What should it do if I disable the TEST system for a while and then enable it?&lt;/em&gt; I’d say it would be silent for that while and then all the muted messages would pop at once. Do you mind if we test it now?&lt;/p&gt;

&lt;p&gt;First, let it show some messages then disable the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEST&lt;/code&gt; system:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-3/unexpected-filter-behavior-unfiltered-messages.png&quot; alt=&quot;Unexpected behavior on filter (unfiltered messages)&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After 5 seconds, let’s enable it again.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-3/unexpected-filter-behavior-missing-messages.png&quot; alt=&quot;Unexpected behavior on filter (missing messages)&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Can you spot the issues?&lt;/p&gt;

&lt;p&gt;The first screenshot shows how we wanted to filter &lt;em&gt;out&lt;/em&gt; the messages with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEST&lt;/code&gt; system but the ones before we disabled it are still there.&lt;/p&gt;

&lt;p&gt;The second one shows how the messages between timestamps &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3651&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8797&lt;/code&gt; are gone! It’s like they weren’t registered at all! Why is that?&lt;/p&gt;

&lt;p&gt;If you remember, we created an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ICollectionView&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; list. When we created it, the filter was executed and it’s executed again when a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; is added to the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;When we disabled the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEST&lt;/code&gt; system, new items didn’t fulfill the predicate but we didn’t re-evaluate it for the existent ones. When we enabled it again, only the new ones are evaluated and not the ones that were discarded while it was disabled (although they were still stored in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; list).&lt;/p&gt;

&lt;p&gt;So, how do we fix this issue?&lt;/p&gt;

&lt;h3 id=&quot;inotifypropertychanged&quot;&gt;INotifyPropertyChanged&lt;/h3&gt;

&lt;p&gt;We’ve seen how our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogSystem.Enabled&lt;/code&gt; property was modified when we interacted with the checkbox. Our goal is to re-evaluate the filter whenever this happens so it’s applied to the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To do this we need to allow &lt;em&gt;whoever is interested&lt;/em&gt; to listen to changes in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enabled&lt;/code&gt; property. WPF has an interface called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INotifyPropertyChanged&lt;/code&gt; that lets us execute an event whenever this happens. We’d have to refactor our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogSystem&lt;/code&gt; class as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogSystem&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PropertyChangedEventHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;m_enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nf&quot;&gt;PropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Enabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When inheriting from this interface we have a new event handler called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyChanged&lt;/code&gt; that lets others listen to the changes we decide to trigger.&lt;/p&gt;

&lt;p&gt;Remember our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.ConfigureSystems&lt;/code&gt; method where we created our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogSystem&lt;/code&gt; entries? That’s where we’ll subscribe to changes.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;systems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ForEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LogSystem&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogSystem&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OnSystemEnableChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;LogSystems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnSystemEnableChanged&lt;/code&gt; would look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnSystemEnableChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PropertyChangedEventArgs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;FilteredLogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Refresh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Refresh&lt;/code&gt; recreates the &lt;em&gt;view&lt;/em&gt; by re-evaluating the predicate against the source collection. This way, when we disable the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEST&lt;/code&gt; system we’ll have an empty list and when we re-enable it we’ll have all items even when we weren’t seeing them.&lt;/p&gt;

&lt;p&gt;Great job! Now you’ve got filters by system in an auto-scrolling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt;!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;We’ve gone through some useful functionalities for our window, but we’re missing an interesting one: log levels with colors!&lt;/p&gt;

&lt;p&gt;Mind joining me in the next post of the series to complete it?&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="Log" /><category term="WPF" /><category term="CSharp" /><category term="MVVM" /><category term="Class Library" /><category term="Filter" /><category term="System" /><category term="Checkbox" /><summary type="html">Configure the log window from the host application and add useful functionality like filters and auto-scroll</summary></entry><entry><title type="html">Log window from scratch: from standalone to class library</title><link href="https://metanokid.github.io/coding-scars/log-window-2/" rel="alternate" type="text/html" title="Log window from scratch: from standalone to class library" /><published>2018-06-15T00:00:00+00:00</published><updated>2018-06-15T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/log-window-2</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/log-window-2/">&lt;p&gt;Hello again! I was waiting for you to continue with our Log Window!&lt;/p&gt;

&lt;p&gt;In the last post we created the basic UI and functionality. However, that window does little by itself so we want to &lt;em&gt;convert it into a component&lt;/em&gt; we can plug into other projects. That way, we could focus on building a nice project with the help of a logging window!&lt;/p&gt;

&lt;p&gt;Grabbed a drink? Then we’re ready to start!&lt;/p&gt;

&lt;h1 id=&quot;the-host-program&quot;&gt;The host program&lt;/h1&gt;

&lt;p&gt;We said we wanted to use the window from another project, right? Why don’t we start building that first?&lt;/p&gt;

&lt;p&gt;Let’s add a new C# project into our solution. This time, we don’t want a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WPF Application&lt;/code&gt; but a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Console Application&lt;/code&gt;. Let’s give it a meaningful name… like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HostProgram&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We’ll have a new project with a new autogenerated &lt;em&gt;Program.cs&lt;/em&gt; file. Let’s keep it and modify its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main&lt;/code&gt; to something familiar:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, world!\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, set this project as the startup project: one way is to right-click on the project then select &lt;em&gt;Set as StartUp Project&lt;/em&gt;. Then run the solution and you’ll have the expected message in the console. Nothing new here.&lt;/p&gt;

&lt;p&gt;What if we wanted to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; class we created in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt; project? Can we do this?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Sample message!&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[{0}][{1}] {2}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Unfortunately we can’t… yet.&lt;/p&gt;

&lt;h2 id=&quot;referencing-projects&quot;&gt;Referencing projects&lt;/h2&gt;

&lt;p&gt;For our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HostProgram&lt;/code&gt; to be able to use classes from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt; project we need to connect them somehow. To do so, expand the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HostProgram&lt;/code&gt; project and right-click &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;References&lt;/code&gt;, select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add Reference...&lt;/code&gt;. Now enable the checkbox next to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt; project and accept the dialog.&lt;/p&gt;

&lt;p&gt;Our code still doesn’t compile, but now we can add this line:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;LogWindowUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Because, if you remember, our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; class was defined inside a namespace called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can happily run our solution now and the formatted log message will show up in the console. We’re getting there!&lt;/p&gt;

&lt;h1 id=&quot;breaking-it-up&quot;&gt;Breaking it up&lt;/h1&gt;

&lt;p&gt;Okay, we’ve connected our projects but our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt; one is still a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Windows Application&lt;/code&gt; and we want to make it a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt;. We’ll do that now, but first you should know everything will be broken until we complete some steps.&lt;/p&gt;

&lt;p&gt;Start by opening the Properties page in the project (one way is double-clicking the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Properties&lt;/code&gt; entry when you expand the project). Select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt; from the &lt;em&gt;Output type&lt;/em&gt; control, then save.&lt;/p&gt;

&lt;p&gt;You will now see several errors in the &lt;em&gt;Error List&lt;/em&gt; panel. The first one says:&lt;/p&gt;

&lt;p class=&quot;notice--primary&quot;&gt;&lt;em&gt;Library project file cannot specify ApplicationDefinition element.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;removing-appxaml&quot;&gt;Removing App.xaml&lt;/h2&gt;

&lt;p&gt;Do you remember, from previous post, that the startup of the UI felt like &lt;em&gt;Magic&lt;/em&gt; because we apparently never said where it should start? Remember the two concepts we discussed: &lt;em&gt;Application&lt;/em&gt; and &lt;em&gt;Window&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;One of the files, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml&lt;/code&gt;, defines the entry point and which &lt;em&gt;Window&lt;/em&gt; to display when we launch the program. Because we’ll be using this project as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt;, the host program will be responsible of managing the life cycle itself. We’ll just provide tools for it to work. So, delete &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml&lt;/code&gt; and the error will go away.&lt;/p&gt;

&lt;p&gt;Except not! It looks like it has deleted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml.cs&lt;/code&gt; as well and we don’t have an &lt;em&gt;Application&lt;/em&gt; anymore!&lt;/p&gt;

&lt;h2 id=&quot;creating-appcs&quot;&gt;Creating App.cs&lt;/h2&gt;

&lt;p&gt;Let’s add a new class called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App&lt;/code&gt; in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt; project with this code, pretty similar to what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml.cs&lt;/code&gt; had:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;LogWindowUI&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Application&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With this, all errors will go away and we can run our console-based &lt;em&gt;hello log&lt;/em&gt;. Impressive :)&lt;/p&gt;

&lt;p&gt;But, how do we connect them now?&lt;/p&gt;

&lt;h1 id=&quot;showing-window-from-host-program&quot;&gt;Showing window from host program&lt;/h1&gt;

&lt;p&gt;So far we’ve gained access to the classes in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI&lt;/code&gt; project from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HostProgram&lt;/code&gt; one. However, we’re left with a sad log message in the console and no WPF window.&lt;/p&gt;

&lt;p&gt;To keep things clean, we should expose some class that lets us create the window, send it messages and close it when necessary instead of dealing with the internal classes from the outside. We only want to have one window at the same time, so… guess which design pattern we’ll be using?&lt;/p&gt;

&lt;h2 id=&quot;singleton-pattern&quot;&gt;Singleton pattern&lt;/h2&gt;

&lt;p&gt;You may have heard of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Singleton_pattern&quot; target=&quot;_blank&quot;&gt;Singleton pattern&lt;/a&gt; before. It allows us to restrict the instantiation of a class to a single object. It’s used when it doesn’t make sense to have several instances of one class, commonly when you’re defining a manager of some sorts or a wrapper to an underlying system which should have a single entry point.&lt;/p&gt;

&lt;p&gt;Bob Nystrom (&lt;a href=&quot;https://twitter.com/munificentbob&quot; target=&quot;_blank&quot;&gt;@munificentbob&lt;/a&gt;), in his &lt;a href=&quot;http://gameprogrammingpatterns.com&quot; target=&quot;_blank&quot;&gt;Game Programming Patterns&lt;/a&gt;, has &lt;a href=&quot;http://gameprogrammingpatterns.com/singleton.html&quot; target=&quot;_blank&quot;&gt;an awesome chapter&lt;/a&gt; about the pattern so go and read it if you want to know the good and bad parts about it.&lt;/p&gt;

&lt;p&gt;A simple C# implementation of the pattern is this one:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoggerUI&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            	&lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, this &lt;em&gt;lazy initialization&lt;/em&gt; (the instance isn’t created until the first piece of code accesses it by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Instance&lt;/code&gt; property) takes life cycle control from us (and isn’t thread safe). We’d want to explicitly control when the instance is created and when it’s destroyed. Let’s make it so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LoggerUI&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;LoggerUI not initialized&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;LoggerUI already initialized&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    	&lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;LoggerUI already destroyed!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_instance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This way, we control the life cycle ourselves. It isn’t thread safe either, but we’ll be sure to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Initialize&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Destroy&lt;/code&gt; in a single-thread part of the program. Let’s also add a new method to test it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;calling-from-host&quot;&gt;Calling from host&lt;/h2&gt;

&lt;p&gt;For now, our host program just has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main&lt;/code&gt; function from which we’ll call everything:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// intialization step&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// [...] some other code in our program&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// [...] some other code in our program&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// teardown step&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And it works as expected, yay! Now, let’s show the window again!&lt;/p&gt;

&lt;h2 id=&quot;sta-application-and-window&quot;&gt;STA, Application and Window&lt;/h2&gt;

&lt;p&gt;Remember the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml&lt;/code&gt; file we had before we broke everything? If we stripped it a bit we’d have this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Application&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x:Class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LogWindowUI.App&quot;&lt;/span&gt;
             &lt;span class=&quot;na&quot;&gt;StartupUri=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MainWindow.xaml&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Application&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Which is telling the runtime to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogWindowUI.App&lt;/code&gt; class as the &lt;em&gt;Application&lt;/em&gt; and then display the &lt;em&gt;Window&lt;/em&gt; defined at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml&lt;/code&gt; (whose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x:Class&lt;/code&gt; attribute points to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml.cs&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;So it looks like we need an &lt;em&gt;Application&lt;/em&gt; that displays a &lt;em&gt;Window&lt;/em&gt;. Okay, what else?&lt;br /&gt;
In the previous post we mentioned WPF uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Single Thread Apartment&lt;/code&gt; model: any object created within a thread can only be modified from that thread (the &lt;em&gt;UI Thread&lt;/em&gt;). Guess we need one of those too.&lt;/p&gt;

&lt;p&gt;We’ve defined our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; singleton class as the entry point to our WPF library. We could have the &lt;em&gt;Application&lt;/em&gt; as a member of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; and tie its creation to the creation of the singleton itself. Something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetApartmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApartmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Basically, just what we said we’d do. But there’s a catch.&lt;/p&gt;

&lt;p&gt;When we run this code, it’s not guaranteed the &lt;em&gt;Application&lt;/em&gt; and its &lt;em&gt;Window&lt;/em&gt; are running after we call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI.Initialize()&lt;/code&gt; (which ends up calling the constructor and thus this code). If we were to start logging stuff right after calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Initialize&lt;/code&gt; it could fail because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m_application&lt;/code&gt; could be uninitialized. Ah, the joy of multithreading.&lt;/p&gt;

&lt;p&gt;One way of solving this issue is to wait for the &lt;em&gt;Application&lt;/em&gt; to be ready. After all, it’s part of the initialization process. We can use an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AutoResetEvent&lt;/code&gt; to wait in our &lt;em&gt;main thread&lt;/em&gt; until the &lt;em&gt;Application&lt;/em&gt; and &lt;em&gt;Window&lt;/em&gt; are running. We could rewrite the constructor with this code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AutoResetEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;windowCreatedEvent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AutoResetEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// notify they are created before we block this thread&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;windowCreatedEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetApartmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApartmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// wait until the application and window are created&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;windowCreatedEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WaitOne&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note how we’ve separated the &lt;em&gt;Window&lt;/em&gt; creation from the &lt;em&gt;Application&lt;/em&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Run&lt;/code&gt; method. When you create a &lt;em&gt;Window&lt;/em&gt; it starts hidden, so we must call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Show&lt;/code&gt; ourselves or let &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Run&lt;/code&gt; do it for us. Oh, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Run&lt;/code&gt; blocks until the &lt;em&gt;Window&lt;/em&gt; is closed, so we must signal the event before doing it. The &lt;em&gt;Application&lt;/em&gt; is already created by then so we can start manipulating it.&lt;/p&gt;

&lt;p&gt;If we were to run the program now we’d see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-2/console-and-window-base.png&quot; alt=&quot;Unconnected console and WPF window&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All that’s left is sending messages from the host program to our WPF library instead of mocking them!&lt;/p&gt;

&lt;h2 id=&quot;connecting-logs&quot;&gt;Connecting logs&lt;/h2&gt;

&lt;p&gt;As you can see in the previous picture, we had a way of adding messages to the window. For testing purposes we did that in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt;’s constructor. Let’s delete that code now, so there’s nothing sending messages.&lt;/p&gt;

&lt;p&gt;Now, in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LoggerUI&lt;/code&gt; singleton class, let’s update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add&lt;/code&gt; method:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// add it to the window via UI thread&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginInvoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;delegate&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// window can be closed already&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddLogEntry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Did you notice the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dispatcher.BeginInvoke&lt;/code&gt; thing we mentioned in the previous post?&lt;/p&gt;

&lt;p&gt;Also, create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.AddLogEntry&lt;/code&gt; like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AddLogEntry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Our current code won’t compile if we do this, because in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main&lt;/code&gt; function we’re still using the old version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add&lt;/code&gt;. Let’s fix it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Run it and we have this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-2/console-and-window-connected.png&quot; alt=&quot;Connected console and WPF window&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Or we could do this as well:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LoggerUI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.0f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-2/console-and-window-several-messages.png&quot; alt=&quot;Connected console and WPF window with several messages&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yay! It works! Looks like we did it, awesome job!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;In this post we’ve managed to convert our WPF project into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt; we can plug into other projects and log whatever we want from that project. We’ve also defined a Singleton entry point for the library and created the &lt;em&gt;UI Thread&lt;/em&gt; in which the &lt;em&gt;Application&lt;/em&gt; and &lt;em&gt;Window&lt;/em&gt; live.&lt;/p&gt;

&lt;p&gt;In the next entry we’ll work on adding some extra functionality to the window, like colors, filters and auto-scroll.&lt;/p&gt;

&lt;p&gt;See you then!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="Log" /><category term="WPF" /><category term="CSharp" /><category term="MVVM" /><category term="Class Library" /><summary type="html">Convert a WPF Application into a Class Library we can use from other projects</summary></entry><entry><title type="html">Log window from scratch: basic window</title><link href="https://metanokid.github.io/coding-scars/log-window-1/" rel="alternate" type="text/html" title="Log window from scratch: basic window" /><published>2018-06-13T00:00:00+00:00</published><updated>2018-06-13T00:00:00+00:00</updated><id>https://metanokid.github.io/coding-scars/log-window-1</id><content type="html" xml:base="https://metanokid.github.io/coding-scars/log-window-1/">&lt;p&gt;Welcome back, dear reader!&lt;/p&gt;

&lt;p&gt;In this post we’ll create a basic standalone log window in WPF that we’ll use as the foundation of our project. I recommend you checking out the previous entry in the series if you want to know the motivation or the road map.&lt;/p&gt;

&lt;p&gt;We’ll end up with this, after the post:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-1/sample-data.png&quot; alt=&quot;Sample display data&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;creating-the-base-project&quot;&gt;Creating the base project&lt;/h1&gt;

&lt;p&gt;We’re using WPF, so start up your Visual Studio and create a &lt;em&gt;New project&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Under &lt;em&gt;Templates&lt;/em&gt; find &lt;em&gt;Visual C#&lt;/em&gt; and then select &lt;em&gt;WPF Application&lt;/em&gt;. Choose a nice name for your brand new project (and solution) and accept the wizard.&lt;/p&gt;

&lt;p&gt;After it finishes loading up, you’ll have a solution with a project and several files. These are the basics of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Windows_Presentation_Foundation&quot;&gt;Windows Presentation Foundation (WPF)&lt;/a&gt; project. There are two basic concepts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Application: the WPF program itself, the entry point to the framework.&lt;/li&gt;
  &lt;li&gt;Window: a piece of UI where controls are displayed so user can interact with the program.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the project you have three files related to the Application:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.config&lt;/code&gt;: general configuration, metadata and settings for the application (database connection strings, .NET version, …).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml&lt;/code&gt;: declares which Window to display as it starts and extra data resources.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml.cs&lt;/code&gt;: C# class for this application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also two files related to the Window:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml&lt;/code&gt;: declares the controls for the window, their properties and some behavior.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml.cs&lt;/code&gt;: C# class for this Window, which will hold its custom logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, when I started learning the little bit of WPF I know now, it felt like &lt;em&gt;Magic&lt;/em&gt;. Where is the entry point defined? There’s no &lt;em&gt;Main&lt;/em&gt; function! How does it know which window to display? Hint: it all starts in the &lt;em&gt;Properties&lt;/em&gt; page and ends up in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StartupUri&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App.xaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For now, we’ll just work with these default files and configurations as a standalone WPF project. In the next post, we’ll convert it to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt; and will learn how the Application-Window relationship works.&lt;/p&gt;

&lt;h1 id=&quot;basic-ui-controls&quot;&gt;Basic UI controls&lt;/h1&gt;

&lt;p&gt;Okay, so we have the default WPF stuff. Let’s start creating our UI!&lt;/p&gt;

&lt;p&gt;If you remember, the bare minimum we wanted to have a tabular display of the log data. Maybe with three columns:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Timestamp: can be any kind of timestamp we want from &lt;em&gt;seconds since startup&lt;/em&gt; to &lt;em&gt;full date timestamp&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;System/tag: each message can be tagged with a key, like the system it comes from (i.e. &lt;em&gt;net&lt;/em&gt; or &lt;em&gt;render&lt;/em&gt;).&lt;/li&gt;
  &lt;li&gt;Message: the log data itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s open the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml&lt;/code&gt; file now. The Designer will open for us showing two panels: one with the graphical representation of our &lt;em&gt;Window&lt;/em&gt; and one with the XAML markup. It looks something like this (some names will differ):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Window&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x:Class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LogWindowUI.MainWindow&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;xmlns:x=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;xmlns:d=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/expression/blend/2008&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;xmlns:mc=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;xmlns:local=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;clr-namespace:LogWindowUI&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;mc:Ignorable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;d&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;Title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MainWindow&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;350&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;525&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Grid&amp;gt;&lt;/span&gt;
        
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Window&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt; into the XAML panel with this markup:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Window&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Grid&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;ListView&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x:Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LogEntryList&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;ListView.View&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;GridView&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;GridViewColumn&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Header=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Timestamp&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;70&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/GridViewColumn&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;GridViewColumn&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Header=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;System&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;70&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/GridViewColumn&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;GridViewColumn&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Header=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Message&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;440&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/GridViewColumn&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/GridView&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ListView.View&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ListView&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Window&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And this is how it looks when we run the program:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-1/base-window.png&quot; alt=&quot;Base window&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Alright, we’re on track!&lt;/p&gt;

&lt;h1 id=&quot;mvvm-pattern&quot;&gt;MVVM pattern&lt;/h1&gt;

&lt;p&gt;So far we’ve just defined how we want our window to look like but it doesn’t do anything just yet. We need to understand how WPF handles data, first.&lt;/p&gt;

&lt;p&gt;Although WPF lets you tie your UI and your logic in a tightly-coupled way (code knows which control to update when something happens, control knows which data to update, …), the MVVM way is preferred.&lt;/p&gt;

&lt;p&gt;MVVM stands for &lt;a href=&quot;https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel&quot; target=&quot;_blank&quot;&gt;Model-View-ViewModel&lt;/a&gt; and it’s an architectural pattern that helps separate the UI representation (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt;) from the program logic and its data (the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt;). The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; is kind of a &lt;em&gt;converter&lt;/em&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; (and handles the &lt;em&gt;presentation logic&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;In other words, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt; is connected with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt;, which is connected to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt;. Whenever the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt; changes, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; notices and notifies the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; to update accordingly. When the user interacts with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; is modified which, in turn, ends up in an update of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How does this affect us? Well, first of all, let’s understand which one of them maps to which concept in our program.&lt;/p&gt;

&lt;h2 id=&quot;model&quot;&gt;Model&lt;/h2&gt;

&lt;p&gt;For us, each log entry is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt;. It has a timestamp, a system and a message (remember last screenshot?).&lt;/p&gt;

&lt;p&gt;In other words, this is our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LogEntry&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;view&quot;&gt;View&lt;/h2&gt;

&lt;p&gt;If you have a look at the previous XAML code we’ve listed, you can see we created a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt; called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntryList&lt;/code&gt;. Suspicious names, huh? If we take last screenshot and only keep our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt;, we’d have this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-1/mvvm-view.png&quot; alt=&quot;View in the MVVM pattern&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;viewmodel&quot;&gt;ViewModel&lt;/h2&gt;

&lt;p&gt;Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntryList&lt;/code&gt; control takes any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEnumerable&lt;/code&gt; object as its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ItemsSource&lt;/code&gt; and displays it. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; relies on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; notifying of a data change to update its visual representation. So, if we used a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;LogEntry&amp;gt;&lt;/code&gt; we’d see nothing when we add a new item: it doesn’t notify anyone.&lt;/p&gt;

&lt;p&gt;WPF comes with an interesting collection called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ObservableCollection&amp;lt;T&amp;gt;&lt;/code&gt;. It knows how to notify of a data change in the collection itself (an element is added or removed). So, open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml.cs&lt;/code&gt; and add this property in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt; class:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ObservableCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this case, we could say that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt; is also acting as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; because we’re using it directly as part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ObservableCollection&lt;/code&gt;. However, we could have a hard separation between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; if we were doing more than just showing data (like having extra properties only relevant to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; or a data conversion from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Model&lt;/code&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In future entries of the series we’ll see concrete examples of custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;displaying-logs&quot;&gt;Displaying logs&lt;/h1&gt;

&lt;p&gt;Okay, now that we know what’s what, let’s get some messages on screen!&lt;/p&gt;

&lt;p&gt;First of all, let’s hardcode a message we’ll display. Open the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt; constructor and make it this one:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;InitializeComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ObservableCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// tie View with ViewModel&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogEntryList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ItemsSource&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// add test data&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.1f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, codingScars!&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When we run the program this is what’s displayed:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-1/view-weird-data.png&quot; alt=&quot;Weird data on View&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s because we haven’t told the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; how to display each property of an individual entry. To do so, let’s modify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow.xaml&lt;/code&gt; file and update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt; control with this code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LogEntryList&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridViewColumn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Timestamp&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;70&quot;&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;DisplayMemberBinding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Timestamp}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridViewColumn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridViewColumn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;System&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;70&quot;&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;DisplayMemberBinding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding System}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridViewColumn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridViewColumn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Message&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;440&quot;&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;DisplayMemberBinding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{Binding Message}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridViewColumn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GridView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DisplayMemberBinding&lt;/code&gt; attribute defines which data to display in a column. With the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{Binding Message}&lt;/code&gt; value, we’re telling WPF to look for a Property called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Message&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntry&lt;/code&gt; object. Thank Reflection for that! Please note, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{Binding ...}&lt;/code&gt; is used to connect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ViewModel&lt;/code&gt; and it can be done with properties other than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DisplayMemberBinding&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run it again and it will show this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-1/view-binding.png&quot; alt=&quot;Hello, world! in WPF&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yay! We’ve got it!&lt;/p&gt;

&lt;h2 id=&quot;live-update&quot;&gt;Live update&lt;/h2&gt;

&lt;p&gt;Okay, okay, we’ve displayed some text, but it’s not displaying anything &lt;em&gt;live&lt;/em&gt;. Why don’t we do that now?&lt;/p&gt;

&lt;p&gt;First of all, remove the code that adds an entry to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; collection. Let’s now create a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Thread&lt;/code&gt; that will be adding entries to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;This is the code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// add test data&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.1f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Sample message!&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We run it and… boom! The program crashes! Why is that? What does this error mean?&lt;/p&gt;

&lt;p class=&quot;notice--primary&quot;&gt;&lt;em&gt;This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;sta&quot;&gt;STA&lt;/h1&gt;

&lt;p&gt;WPF uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Single Thread Apartment&lt;/code&gt; model. This means that, any object that’s created within a thread can only be modified by that thread. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Application&lt;/code&gt; is running in what we call the &lt;em&gt;UI Thread&lt;/em&gt;, which is the main one in our case. Because we’ve created our own thread, we can’t modify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LogEntries&lt;/code&gt; directly: this new thread doesn’t own the collection.&lt;/p&gt;

&lt;p&gt;To make it work, let’s change the code to this one:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// add test data&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginInvoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;delegate&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.1f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Sample message!&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Run it again and… it works!&lt;/p&gt;

&lt;h2 id=&quot;dispatcher&quot;&gt;Dispatcher&lt;/h2&gt;

&lt;p&gt;Whenever we want some code to be executed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UI Thread&lt;/code&gt; we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dispatcher&lt;/code&gt; object from the &lt;em&gt;Application&lt;/em&gt; instance to queue the actions we want to perform.&lt;/p&gt;

&lt;p&gt;There are two important methods to queue actions: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BeginInvoke&lt;/code&gt; is asynchronous and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Invoke&lt;/code&gt; is synchronous.&lt;/p&gt;

&lt;h2 id=&quot;final-test&quot;&gt;Final test&lt;/h2&gt;

&lt;p&gt;So, now that we know how it works, let’s have a more complete example!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// add test data&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ticks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ticks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Random&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BeginInvoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;delegate&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;LogEntries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LogEntry&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Timestamp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ticks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ticks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TicksPerSecond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Sample message!&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Running it will show something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://metanokid.github.io/coding-scars//assets/images/per-post/log-window-1/sample-data.png&quot; alt=&quot;Sample display data&quot; class=&quot;align-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Phew! Not bad! Good job :)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Through the post we’ve created the foundation of our log window from scratch and learned about the MVVM pattern. In the next post we’ll take this standalone WPF program and make it a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Class Library&lt;/code&gt; that we can use from a &lt;em&gt;host program&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading! See you then!&lt;/p&gt;</content><author><name>Carlos Fraguas</name></author><category term="Toolbox" /><category term="Log" /><category term="WPF" /><category term="CSharp" /><category term="MVVM" /><category term="Binding" /><summary type="html">Simple WPF standalone program to display log entries</summary></entry></feed>