<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Nothing ventured, nothing gained</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/jonwis/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/jonwis/feed.xml</link>
    <description />
    <lastBuildDate>Tue, 16 Apr 2019 05:13:46 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Getting ancient remote branches in git</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/getting-ancient-remote-branches-in-git</link>
      <pubDate>Mon, 11 May 2015 15:43:31 GMT</pubDate>
      <dc:creator><![CDATA[Jon Wiswall MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2015/05/11/getting-ancient-remote-branches-in-git/</guid>
      <description><![CDATA[My project has 300+ remote branches for a 100-ish person team. That can't possibly be right.&nbsp;...]]></description>
      <content:encoded><![CDATA[<p>My project has 300+ remote branches for a 100-ish person team. That can't possibly be right.&nbsp; Here's some powershell to detect super old branches so I can go annoy their owners about deleting them:</p>
<p>git branch -r | ?{ $_ -notlike "*/HEAD *" } | %{ git log $_.Trim() -n 1 --format=format:"%ct %d %h %an %ar" } | Sort-Object</p>
<p>The format is like:</p>
<p>1396576284&nbsp; (origin/release) b3a96ad&nbsp;&lt;name&gt; 1 year, 1 month ago<br />1402418261&nbsp; (origin/&lt;alias&gt;/Keyboard2) 83374b7&nbsp;&lt;name&gt; 11 months ago<br />1402938550&nbsp; (origin/&lt;alias&gt;/nopackages) 630cca0&nbsp;&lt;name&gt; 11 months ago<br />1403027117&nbsp; (origin/&lt;alias&gt;/SomeLongCompletedIntegration) ab7a735&nbsp;&lt;name&gt; 11 months ago</p>
<p>Et voila, now I can find &amp; zap branches with "git push origin --delete branchname"</p>]]></content:encoded>
    </item>
    <item>
      <title>Stripe-sets via Storage Spaces</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/stripe-sets-via-storage-spaces</link>
      <pubDate>Thu, 22 May 2014 23:42:10 GMT</pubDate>
      <dc:creator><![CDATA[Jon Wiswall MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2014/05/22/stripe-sets-via-storage-spaces/</guid>
      <description><![CDATA[I had a bunch of spinning disks sitting&nbsp;around I wanted to stripe together as build output...]]></description>
      <content:encoded><![CDATA[<p>I had a bunch of spinning disks sitting&nbsp;around I wanted to stripe together as build output targets.&nbsp;&nbsp; The RAID hardware in my desktop is known to be flaky, so I decided to try out Storage Spaces.&nbsp; The default "simple" storage space doesn't actually span all disks in the pool - it attempts to keep copies of data together, and is optimized for making a volume that's larger than any individual disk.</p>
<p>Some bing-ing and stack-overflow later and I came up with the following powershell.</p>
<pre class="scroll"><code class="cplusplus"># Remove all pool members<br />Get-StoragePool -FriendlyName MyPool | Get-VirtualDisk | Remove-VirtualDisk<br /> <br />"x","y","z" | %{<br /> $letter = $_<br /> New-VirtualDisk -StoragePoolFriendlyName MyPool -ResiliencySettingName Simple -FriendlyName output_disk -Size 500gb -ProvisioningType Fixed -NumberOfDataCopies 1 -NumberOfColumns 4 | Get-Disk | Initialize-Disk -Passthru | New-Partition -DriveLetter $letter -UseMaximumSize<br /> $driveletter = $letter+":"<br /> format $driveletter /fs:ntfs /q /x /a:64K<br />} </code></pre>
<p>Note that you'll need to have created the pool with the name "MyPool".&nbsp; Replace the "-Size" parameter with your desired size, and set "-NumberOfColumns" to the number of physical disks in the pool.&nbsp; (I'm sure I could determine that from the pool object in the future.</p>
<p>Et voila - a real actual stripeset!&nbsp; I had three builds, so I used x/y/z as the outputs.</p>
<p>FWIW, this setup got me within ~10% of the build time using an SSD for the output, without the SSD cost.</p>]]></content:encoded>
    </item>
    <item>
      <title>Super-sharpening(?) the image</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/super-sharpening-the-image</link>
      <pubDate>Sat, 25 Jul 2009 02:15:41 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2009/07/25/super-sharpening-the-image/</guid>
      <description><![CDATA[I may have forgotten to mention it, but my expertise is not in image processing.&#160; The people...]]></description>
      <content:encoded><![CDATA[<p>I may have forgotten to mention it, but my expertise is <em>not</em> in image processing.&#160; The people who know better will likely tsk mightily at this and upcoming posts. My apologies. =)</p>  <p>Last time got me a b&amp;w-converted version of a picture, but didn’t do much with it.&#160; Next up, I need a sequence of integer values from each row in the image for more processing.&#160; Eventually I want to convert those numbers to simple on-and-off values for processing.&#160; For starters, it seems like I should be able to convert each RGB pixel value into its 0-255 greyscale equivalent.&#160; Once I’ve got a byte, my simple theory is that squaring that 8-bit grayscale will produce a 16-bit ushort to process.</p>  <p>Thus:</p>  <ol>   <li>Access the bits of the image </li>    <li>Convert each pixel to greyscale </li>    <li>Push “light” pixels towards some high-value, push “dark” pixels down towards some low-value </li>    <li>Wrap that up in some sort of enumerator.</li> </ol>  <p>With a little yield fun, I ended up with an enumerator that produces ushort[] from each row in the image.&#160; </p>  <ul>   <li>Why ushorts? 255*255 = 65025, which is less than 65535.&#160; </li>    <li>Why not put the RowData function into the enumerator with the yield?&#160; Because C# doesn’t allow unsafe code blocks in iterators.&#160; Wierd.</li>    <li>I’ll need to put the Bitmap acquisition and the LockData outsidethe enumerator, but that’s OK.</li> </ul>  <pre>public class ImageRowEnumerator : IEnumerable&lt;ushort[]&gt; {
    BitmapData _bmpData;
    int _rowSkip;

    public ImageRowEnumerator(BitmapData b, int skip) {
        _bmpData = b;
        _rowSkip = skip;
    }

    public IEnumerator&lt;ushort[]&gt; GetEnumerator() {
        for (int row = 0; row &lt; _bmpData.Height; row += _rowSkip)
            yield return RowData(_bmpData, row);
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }

    unsafe ushort[] RowData(BitmapData bmpData, int row) {
        ushort[] row_data = new ushort[_bmpData.Width];
        byte* pData = (byte*)bmpData.Scan0 + (bmpData.Stride * row);
        for (int col = 0; col &lt; _bmpData.Width; col++, pData += 3) {
            ushort color = (ushort)((pData[0] * .3f) + (pData[1] * .59f) + (pData[2] * .11f));
            row_data[col] = (ushort)(color * color);
        }
        return row_data;
    }
}</pre>

<p>Next time, converting from the ushort values to on/off.&#160; It’s not just checking for 50%.</p>]]></content:encoded>
    </item>
    <item>
      <title>Converting an Image (well, Bitmap really) to Grayscale</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/converting-an-image-well-bitmap-really-to-grayscale</link>
      <pubDate>Sat, 18 Jul 2009 16:59:50 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2009/07/18/converting-an-image-well-bitmap-really-to-grayscale/</guid>
      <description><![CDATA[First thought – convert the picture to greyscale and increase the contrast to help any kind of...]]></description>
      <content:encoded><![CDATA[<p>First thought – convert the picture to greyscale and increase the contrast to help any kind of edge-detection work.&#160; Some searching found me <a href="http://bobpowell.net/image_contrast.htm">Bob Powell's handy guide to increasing contrast</a> and <a href="http://bobpowell.net/grayscale.htm">converting to grayscale</a> via ColorMatrix.&#160; With Wikipedia’s explanation of “naive” matrix multiplication in hand I cobbled up a converter that takes a bitmap and returns a grayscaled version.</p>  <pre>    public class GreyscaleBitmap
    {
        // Magic conversion to greyscale matrix
        static float[][] _grayScaleMatrix = new float[][] {
            new float[] {.3f, .3f, .3f, 0, 0},
            new float[] {.59f, .59f, .59f, 0, 0},
            new float[] {.11f, .11f, .11f, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {0, 0, 0, 0, 1}
        };

        // Doubles contrast
        static float[][] _increaseContrast = new float[][] {
            new float[] {2, 0, 0, 0, 0},
            new float[] {0, 2, 0, 0, 0},
            new float[] {0, 0, 2, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {0, 0, 0, 0, 1}
        };

        // Dumb and slow.
        static float[][] MatrixMult2(float[][] first, float[][] second)
        {
            float[][] result = new float[5][];

            for (int i = 0; i &lt; 5; i++)
                result[i] = new float[5];

            for (int j = 0; j &lt; 5; j++)
                for (int k = 0; k &lt; 5; k++)
                    for (int i = 0; i &lt; 5; i++)
                        result[i][j] += first[i][k] * second[k][j];

            return result;
        }

        // Only bother making one of these
        static ColorMatrix _matrix = new ColorMatrix(MatrixMult2(_grayScaleMatrix, _increaseContrast));

        // Cache this as well?
        static ImageAttributes GetAttributes()
        {
            ImageAttributes result = new ImageAttributes();
            result.SetColorMatrix(_matrix);
            return result;
        }

        public static Bitmap Convert(Bitmap bmp)
        {
            Bitmap newBitmap = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format24bppRgb);

            using (Graphics g = Graphics.FromImage(newBitmap))
            {
                Rectangle r = new Rectangle(0, 0, newBitmap.Width, newBitmap.Height);
                g.DrawImage(bmp, r, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, GetAttributes());
            }

            return newBitmap;
        }
    }</pre>

<p>Now, in another world the output image format would be 16bpp grayscale directly, instead of being re-encoded in 24bpp RGB.&#160; As a result, my eventual scanner will have to convert back from RGB to a grayscale value <em>again</em>.&#160; Not a great start, but hey – conversion to grayscale!</p>]]></content:encoded>
    </item>
    <item>
      <title>Voyage of the S.S. UPC Scanner</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/voyage-of-the-s-s-upc-scanner</link>
      <pubDate>Sat, 18 Jul 2009 16:24:59 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2009/07/18/voyage-of-the-s-s-upc-scanner/</guid>
      <description><![CDATA[I got this silly idea in my head last week that I’d take my brand-new high-def handheld video camera...]]></description>
      <content:encoded><![CDATA[<p>I got this silly idea in my head last week that I’d take my brand-new high-def handheld video camera and use it to produce a catalog of books, DVDs, etc. that are lying around the house.&#160; Simple premise – turn on the camera and wave games, DVDs, etc. at it.&#160; Every Nth frame in the video stream, search for UPC codes.&#160; Produce the unique set of codes and look them up in any one of the existing online databases. Poof – a complete record of whatever I’ve got sitting around.</p>  <p>And along the way learn WPF, image manipulation, video processing, LINQ, etc. etc.</p>]]></content:encoded>
    </item>
    <item>
      <title>What's winsxsmanifestcache(something)_blobs.bin?</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/whats-winsxsmanifestcachesomething_blobs-bin</link>
      <pubDate>Tue, 13 Jan 2009 17:00:00 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2009/01/13/whats-winsxsmanifestcachesomething_blobs-bin/</guid>
      <description><![CDATA[Glenn writes:

"What is the c:\windows\winsxs\manifestcache\6.0.6001.18000_001c50b5_blobs.bin file...]]></description>
      <content:encoded><![CDATA[<P>Glenn writes:</P>
<BLOCKQUOTE>
<P>"What is the c:\windows\winsxs\manifestcache\6.0.6001.18000_001c50b5_blobs.bin file and why is it taking up 156Mb on my hard drive? Do I really need a file this big?"</P></BLOCKQUOTE>
<P>That file is used by the Windows Update mechanisms in Vista.&nbsp; It acts like a cache and is capped at a certain size, but it's safe to delete.&nbsp; The next time you turn on or off Windows optional features or take updates from Windows Update it'll reappear.&nbsp;The file will be recreated as necessary to help the servicing system do its work.&nbsp; Maybe in the future it'll be added to the disk-cleaup wizard, but it noticably increases the performance of servicing operations while it's there.</P>
<P>Of course, actually deleting the file is left as an excercise to the reader.</P>]]></content:encoded>
    </item>
    <item>
      <title>Shipping default values in the registry</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/shipping-default-values-in-the-registry</link>
      <pubDate>Wed, 03 Sep 2008 16:04:00 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2008/09/03/shipping-default-values-in-the-registry/</guid>
      <description><![CDATA[Recently, someone asked about how their code should work if a certain configuration setting was...]]></description>
      <content:encoded><![CDATA[<P style="MARGIN: 0in 0in 10pt" class=MsoNormal><FONT size=3><FONT face=Calibri>Recently, someone asked about how their code should work if a certain configuration setting was missing from the registry. The responses were mixed.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>One suggested checking the value of RegQueryValue. Another suggested that the missing value should cause the app to fail. The right answer is "it should use the default value."<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>"But hark!" you say - "the question was about how to deal with the missing default value!"<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>And the answer doesn't change - have a fallback strategy that can still pull a default value out of your ear at runtime.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></FONT></P>
<P style="MARGIN: 0in 0in 10pt" class=MsoNormal><FONT size=3><FONT face=Calibri>Ok then, let's suppose you've done this and now have code that looks like "For this configuration widget, read the current value; if there is no current value, read the default; if there is no default, use &lt;mystery value&gt; instead."<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>That's three levels of decision making, three independent code paths for your test team to validate.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>What if you could just cut out that middle piece and go back to two - a default in-code and a possible per-user override?<o:p></o:p></FONT></FONT></P>
<P style="MARGIN: 0in 0in 10pt" class=MsoNormal><FONT size=3><FONT face=Calibri>This leads me to the following broad statement - <B style="mso-bidi-font-weight: normal">Defaults should be shipped in code, user configurations saved on the device in stable storage. </B><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>Three reasons:<o:p></o:p></FONT></FONT></P>
<P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpFirst><SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3 face=Calibri>1.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3><FONT face=Calibri><B style="mso-bidi-font-weight: normal">Setting a value during setup is a point of failure.</B><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Yes it almost never happens.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>But it happens.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The best setup you can imagine is one done by (logical) xcopy.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Imagine your app being run from a network share.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The vast majority of applications - web apps, for instance - have no "install" step.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>They just start up and use default settings until overridden by a user-initiated configuration step.</FONT></FONT></P>
<P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpMiddle><SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3 face=Calibri>2.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3><FONT face=Calibri><B style="mso-bidi-font-weight: normal">"Reset to known good state" should be "delete all overridden settings and start again."</B><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Apps that have "repair" fail mightily when they try to distinguish important things to keep from unimportant things to keep.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>If the app is able to start up and run correctly from a completely clean state "repair" can be "delete this key, restart the app." </FONT></FONT></P>
<P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1" class=MsoListParagraphCxSpLast><SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3 face=Calibri>3.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3><FONT face=Calibri><B style="mso-bidi-font-weight: normal">Servicing of user-defaults is impossible without an override model</B>.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Imagine a default color value like "blue".<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The user changes her mind and picks "orange" instead.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Later they decide they like "blue" again.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Now imagine an update coming down for your application that changes the default to "white".<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>A naïve updater might look at the old default (blue) and the current setting (blue) and say "aha! They're still on the default, change to white!" which is not what the customer intended.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>They consciously chose "blue".<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Granted, this means your settings model needs a "use default" button, but that's a small price to pay for customer sat.<o:p></o:p></FONT></FONT></P>
<P style="MARGIN: 0in 0in 10pt" class=MsoNormal><FONT size=3><FONT face=Calibri>Every interesting app has some form of configuration the user or the environment can supply it.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Well-designed apps work correctly even when there are no configurations provided at all.<o:p></o:p></FONT></FONT></P>
<P style="MARGIN: 0in 0in 10pt" class=MsoNormal><FONT size=3><FONT face=Calibri>Rude Q&amp;A:<o:p></o:p></FONT></FONT></P>
<P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo2" class=MsoListParagraphCxSpFirst><SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3 face=Calibri>1.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3 face=Calibri>"But I don't want to recompile to change my defaults!"<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Have your default values in a text file in your app deployment unit.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Managed code provides an app configuration model based on yourexe.exe.config, which is reasonably OK.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Others use a .txt file structured like an INF. </FONT></P>
<P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo2" class=MsoListParagraphCxSpMiddle><SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3 face=Calibri>2.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3 face=Calibri>"But I can't possibly change all my code to use an override system!"<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Have you checked?<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>I bet there's one or two interesting functions in your code that read those settings that you could change.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>If there are many functions that all do configuration checks, refactor them into a single point of access where you can do this.</FONT></P>
<P style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 0.5in; mso-list: l1 level1 lfo2" class=MsoListParagraphCxSpLast><SPAN style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin"><SPAN style="mso-list: Ignore"><FONT size=3 face=Calibri>3.</FONT><SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></SPAN><FONT size=3><FONT face=Calibri>"But having defaults in code means image bloat!" A dword in code is maximally 4 bytes in the const data section, less-so if the optimizer inlines uses of it.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>A reg_dword is those four bytes plus the size of the registry value, the key that references it, the parent key of that key, and so on.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>You're trading a small fixed overhead for a larger unknown overhead.<o:p></o:p></FONT></FONT></P>
<P style="MARGIN: 0in 0in 10pt" class=MsoNormal><FONT size=3 face=Calibri>Note: this is orthogonal to registering with the system (such as creating services, registering COM goo, etc.).<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Apps that integrate with the system do need an "announce" step (call it 'install' if you prefer).<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>The announcement-management should be owned, debugged, and tested by a central team.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>Windows, CE, and others all do this wrong today for legacy reasons.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>MSI tries to make this better by requiring you to register COM objects through their tables, but it's a stopgap because they still allow calling into DllRegisterServer.<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>One can imagine a system where a data-driven “announcement” mechanism is the only way to get integrated with the system, and the announcing application gets to run no actual code of its own.</FONT></P>]]></content:encoded>
    </item>
    <item>
      <title>Deleting from the WinSxS directory</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/deleting-from-the-winsxs-directory</link>
      <pubDate>Tue, 02 Jan 2007 15:31:12 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2007/01/02/deleting-from-the-winsxs-directory/</guid>
      <description><![CDATA[In Windows Vista, the directory %windir%\WinSxS has much stronger protection on it than it did in...]]></description>
      <content:encoded><![CDATA[<p>In Windows Vista, the directory %windir%\WinSxS has much stronger protection on it than it did in Windows XP and Server 2003.&nbsp; The owner/group is now a SID named "Trusted Installer", a service SID used to start the TrustedInstaller service.&nbsp; Users other than the trusted installer are granted only generic-read/generic-execute by default.&nbsp; This increased protection ensures that only the trusted installer service is allowed to modify the servicing-related metadata and files.&nbsp; If a limited user could modify a file in the directory, for example, they could convince the servicing stack to overwrite one binary with another when the next administrator comes along to enable the Games for Windows package.</p> <p>Content is added to this directory in response to installing applications, enabling packages in the add-remove-programs UI, and installing Windows Out-of-Band releases.&nbsp; Content is removed from this directory as a result of uninstall + scavenging - a topic for another time.&nbsp; One important note - uninstalling your application or Windows app will not <em>necessarily</em> remove the physical bits from the system.&nbsp; The servicing stack marks the bits as unusable and prevents their use through "normal" means.&nbsp; Files and directories will be removed over time as the servicing system cleans up after itself.&nbsp; Administrators should not, for any reason, take it upon themselves to clean out the directory - <strong>doing so may prevent Windows Update and MSI from functioning properly afterwards</strong>.&nbsp; Preventing accidental deletion from the directory is accomplished by putting a strong security descriptor on the directory that inherits to its children.</p> <p>The directory itself is marked with the <a href="http://msdn2.microsoft.com/en-us/library/aa379567.aspx">SDDL</a>:</p> <ul> <li>O:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464</li> <li>G:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464</li> <li>D:PAI</li> <ul> <li>(A;OICI;FA;;;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464)</li> <li>(A;OICI;0x1200a9;;;BA)</li> <li>(A;OICI;0x1200a9;;;SY)</li> <li>(A;OICI;0x1200a9;;;BU)"</li></ul></ul> <p>That long <a href="http://msdn2.microsoft.com/en-us/library/aa379602.aspx">SID</a> (S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464) is the service sid for Trusted Installer.&nbsp; By parts, that SDDL means "the owner and group are Trusted Installer; there is a&nbsp;<a href="http://msdn2.microsoft.com/en-gb/library/aa379573.aspx">protected</a> and auto-inherit <a href="http://msdn2.microsoft.com/en-gb/library/ms721532.aspx">DACL</a>; the ACEs of that DACL grant the trusted installer full access; the ACEs of the DACL also grant builtin-administrators, local system, and builtin users generic-read and generic-write access;&nbsp;each&nbsp;ACE is also automatically inherited by child containers and child objects."</p> <p>So, the security descriptor on the object will prevent even administrators from creating or deleting objects underneath %windir%\winsxs, which is why even an elevated administrator cannot (by default) delete content.</p> <p>Elevated administrators do have (by default) the <a href="http://msdn2.microsoft.com/en-us/library/aa375728.aspx#privilege_constants">SeTakeOwnership privilege</a> enabled.&nbsp; Such a token could <a href="http://msdn2.microsoft.com/en-us/library/aa379620.aspx">take ownership of anything</a> under %windir%\winsxs.&nbsp; Once the owner, the administrator could then reset the SDDL on the object, granting themselves full access to the&nbsp;object.&nbsp; Of course, the generic LUA administrator token does not allow enabling the "take ownership" privilege, so this is only possible after answering the LUA elevation prompt successfully.</p> <p>I leave it to the intrepid user to figure out the correct combination of "takeown.exe", "icacls.exe", and "rmdir" to actually remove content.</p>]]></content:encoded>
    </item>
    <item>
      <title>On-demand multhreaded critical section creation</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/on-demand-multhreaded-critical-section-creation</link>
      <pubDate>Thu, 27 Apr 2006 21:59:00 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2006/04/27/on-demand-multhreaded-critical-section-creation/</guid>
      <description><![CDATA[A question came up on an internal newsgroup recently - "How do I do on-demand initialization of...]]></description>
      <content:encoded><![CDATA[<P>A question came up on an internal newsgroup recently - "How do I do on-demand initialization of critical sections in a multithread-aware library?"&nbsp; The asker didn't have an explicit Initialize function in which his critical section could be created, and instead wanted to know what the right approach was for creating one on demand. Below I provide a sample of how this could be achieved.&nbsp; Next time, I'll have a "clarification" of the sample that has a better debugging profile.</P>
<p>
<pre>// This structure is only a holder for a pointer for now.
typedef struct _ONETIME_CS {
  CRITICAL_SECTION volatile *Cs;
} ONETIME_CS, *PONETIME_CS;

BOOL InitOnetimeCs(PONETIME_CS pCs) {
  MemoryBarrier();
  if (pCs->Cs == NULL) {
    CRITICAL_SECTION *NewCs;
    NewCs = (CRITICAL_SECTION)HeapAlloc(GetProcessHeap(), 0, sizeof(*NewCs));
    if (NewCs == NULL) {
      SetLastError(ERROR_OUTOFMEMORY);
      return FALSE;
    }
    // InitCs and DeleteCs fail by raising SEH exceptions. When
    // those fly by, make sure to free the heap. The loser of
    // the race deletes the losing CS, and the __finally ensures
    // that it gets freed. The winner sees 'null' from the ICEP,
    // all others get what the winner put there.
    __try {
      PVOID OldCs;
      InitializeCriticalSection(NewCs);
      OldCs = InterlockedCompareExchangePointer(
        (volatile PVOID *)&pCs->Cs, NewCs, NULL);
      if (OldCs == NULL) {
        NewCs = NULL;
      } else {
        DeleteCriticalSection(NewCs);
      }
    } __finally {
      if (NewCs != NULL)
        HeapFree(GetProcessHeap(), 0, (PVOID)NewCs);
    }
  }
  MemoryBarrier();
  return (Guarded->Cs != NULL);
}

BOOL EnterOnetimeCs(PONETIME_CS pCs) {
  if (pCs != NULL) {
    if (!InitOnetimeCs(pCs))
      return FALSE;
  }
  EnterCriticalSection(pCs->Cs);
  return TRUE;
}

VOID LeaveOnetimeCs(PONETIME_CS pCs) {
  LeaveCriticalSection(pCs->Cs);
}

VOID DeleteOnetimeCs(PONETIME_CS pCs) {
  PVOID OldCs;
  // Delete can be multithread-aware as well, so use IEP to
  // atomically swap out the value with NULL.  The winner gets
  // a non-null value back, losers get NULL.
  OldCs = InterlockedExchangePointer(&pCs->Cs, NULL);
  if (OldCs != NULL) {
    DeleteCriticalSection((CRITICAL_SECTION*)OldCs);
    HeapFree(GetProcessHeap(), 0, OldCs);
  }
}

ONETIME_CS g_Cs = { NULL };
DWORD MyThreadProc(PVOID) {
  if (!EnterOnetimeCs(&g_Cs))
    RaiseError(ERROR_INTERNAL_ERROR, 0, 0, NULL);
  // do something
  LeaveOnetimeCs(&g_Cs);
}</pre></p>
<p>This is just another example of "racy initialization" using InterlockedCompareExchangePointer.  Some "racy init" patterns are dangerous - especially those that involve "read after write" of the data that's been initialized.  That's what the memory barrier is there for - it guarantees (expensively) that any writes InitializeCriticalSection might have performed will be written back before the following call to EnterCriticalSection.</p>

<p>This method is cheap, but it does require extra heap and may create a few critical sections when there is contention.  Luckily, the cost in CS creation is about zero in Vista - entering the CS when there is contention is where the real cost lies.  Certain analysis methods are made harder - when the app verifier prints the address of a busted CS, "<tt>ln <i>thataddress</i></tt>" won't tell you which symbol contained the critical section.</p>

<p>Next time, a method that avoids spurious CS creation, allows for "<tt>ln <i>thataddress</i></tt>" on the CS address, and has zero heap cost!</p>]]></content:encoded>
    </item>
    <item>
      <title>DLLs and resource ID 2 manifests</title>
      <link>https://docs.microsoft.com/archive/blogs/jonwis/dlls-and-resource-id-2-manifests</link>
      <pubDate>Wed, 18 Jan 2006 01:53:00 GMT</pubDate>
      <dc:creator><![CDATA[jonwis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jonwis/2006/01/18/dlls-and-resource-id-2-manifests/</guid>
      <description><![CDATA[Manifests at resource ID 2 help simplify the lives&nbsp;of DLL authors who want to consume...]]></description>
      <content:encoded><![CDATA[<P>Manifests at resource ID 2 help simplify the lives&nbsp;of DLL authors who want to consume side-by-side components via static imports. Just before processing your DLL's static imports and calling its entrypoint, the loader will create and activate an activation context based on the manifest that it finds at resource ID 2. This ensures that all your static imports are processed in the correct context - if this wasn't the case, binding your DLL's static imports would be affected by whoever was calling LoadLibrary("yourdll.dll"). Not a big deal, until you find out that they <EM>also </EM>had some dll loaded also called "zop.dll" with an export "Flarn", but whose parameter list looked completely different. The autoactivation ensures that your DLL is bound to the right "zop.dll" with the right "Flarn" export (at least subject to publisher policy.)</P>
<P>The logic (not the implementation) looks something like the following:</P>
<OL>
<LI>LoadLibrary("yourdll.dll") is called by the application 
<LI>"yourdll.dll" is found using using the current context plus the <A href="http://msdn.microsoft.com/library/en-us/dllproc/base/dynamic-link_library_search_order.asp">usual DLL lookup mechanisms.</A> 
<LI>When found, if yourdll.dll is not already loaded into this context, the DLL is mapped. 
<LI><A href="http://msdn.microsoft.com/library/en-us/sbscs/setup/createactctx.asp">CreateActCtx</A> is called using the mapped DLL's HMODULE, passing resource ID MAKEINTRESOURCE(2) as the resource number. 
<LI>If that succeeded, the resulting context is activated. 
<LI>The static imports of "yourdll.dll" are resolved, possibly recursively executing these operations until all the statically referenced DLLs have been loaded. 
<LI>The DLL entrypoint for "yourdll.dll" is invoked. 
<LI>If a context was activated above, it's deactivated. 
<LI>Control returns to the application with an appropriate HMODULE </LI></OL>
<P>You can use any manifest you care to in your resource section. Visual Studio has options for embedding manifests at the right resource ID. Nikola has some tips for doing so in <a href="http://blogs.msdn.com/nikolad/articles/425359.aspx">both makefiles</A> and <a href="http://blogs.msdn.com/nikolad/archive/2005/06/05/425360.aspx">the VS IDE</A>.</P>
<P><A href="http://msdn.microsoft.com/library/en-us/sbscs/setup/publisher_configuration.asp">Publisher policy</A> is of course applied, but <A href="http://msdn.microsoft.com/library/en-us/sbscs/setup/per-application_configuration_on_windows_server_2003.asp">application policy (ie: foo.exe.policy)</A> is not. The usual "look in the app directory for <A href="http://msdn.microsoft.com/library/en-us/sbscs/setup/private_assemblies.asp">private assemblies</A>" logic applies as well, so this works even if your DLL is distributed privately with an application.&nbsp; See also <A href="http://msdn.microsoft.com/library/en-us/sbscs/setup/using_side-by-side_assemblies_as_a_resource.asp">Using Side-By-Side Assemblies as a Resource</A>, which covers when various resource values will be used during the loading and initialization of DLLs and executables.</P>]]></content:encoded>
    </item>
  </channel>
</rss>