<?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>Jeremy Kuhne's Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/jeremykuhne/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/feed.xml</link>
    <description>Thoughts from a developer on .NET.  Coding tidbits (Managed C++, C#, interoping with unmanaged code) and just general things related to .NET, Windows, etc..</description>
    <lastBuildDate>Wed, 14 Mar 2018 04:55:55 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Custom directory enumeration in .NET Core 2.1</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/custom-directory-enumeration-in-net-core-2-1</link>
      <pubDate>Fri, 09 Mar 2018 01:59:18 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=595</guid>
      <description><![CDATA[As discussed in my previous post, this post will cover the new enumeration extensibility...]]></description>
      <content:encoded><![CDATA[As discussed in my <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2018/03/08/system-io-in-net-core-2-1-sneak-peek/">previous post</a>, this post will cover the new enumeration extensibility points.

The extensibility API we're providing is meant to allow building high-performance custom enumerators. The performance gains primarily come through utilizing the new Span types and ref structs to allow relatively safe access to native data, avoiding unnecessary allocations. The API has been designed to be as simple as possible while still maintaining the low-allocation, high-performance primary design goals.
<h3>FileSystemEntry</h3>
File system data is wrapped in the <samp>System.IO.Enumeration.FileSystemEntry</samp> struct. It provides the same set of data that the <samp>FileSystemInfo</samp> classes do, along with some enumeration specific data:

<script src="https://gist.github.com/JeremyKuhne/dab62d0212dc453a57a28f4e9df406ea.js"></script>
<h3>FileSystemEnumerable</h3>
There are a few ways to get <samp>FileSystemEntry</samp> data. The simplest way is through the <samp>System.IO.Enumeration.FileSystemEnumerable</samp> class:

<script src="https://gist.github.com/JeremyKuhne/316298513619f8fec8be53c3bfb1a21a.js"></script>

Basic usage isn't too complicated. Let's suppose you wanted to just get the names (not the full paths) of all the files and directories in a given directory:

<script src="https://gist.github.com/JeremyKuhne/5b649ae68673a617a0afb2547e9bf7c8.js"></script>

You can, of course, write the equivalent functionality using the existing APIs that return <samp>FileSystemInfo</samp> objects (e.g. getting <samp>.Name</samp> off of each), but it comes with significant cost. Writing a custom enumerable only takes a <em>single</em> allocation for each <samp>MoveNext</samp> (the filename). Getting the <samp>Info</samp> objects via existing APIs will allocate much more (the <samp>Info</samp> class, the full path, etc.) and will be slower, particularly on Unix as it will cause another fstat call to fill out data you won't ever use.

To take it another step, lets filter to just files (no directories):

<script src="https://gist.github.com/JeremyKuhne/de0ebe352f984767103c9cd970aedd37.js"></script>

Here is another, potentially more useful, example. Lets say you want to create a helper that allows you to get all files with a set of given extensions:

<script src="https://gist.github.com/JeremyKuhne/fad13691931258e5ca798baac5bd5c1c.js"></script>

Let's suppose you want to count the number of files in a directory. With the new APIs you can write a solution that cuts allocations by 200x or more (yes, by a factor of 200).

<script src="https://gist.github.com/JeremyKuhne/3d8850d9d5795463437b81b94cfa1dd8.js"></script>

The example is a little strange as we need some sort of output transform. I picked <samp>int</samp> as the type and returned 1, but it could be anything, including <samp>string</samp> and <samp>string.Empty</samp> or <samp>null</samp>.

Very similar to the above, we could total up file sizes.

<script src="https://gist.github.com/JeremyKuhne/bc06fc15a2911796cc823150c257db29.js"></script>

The performance characteristics of this last example differ quite a bit from Unix to Windows. Allocations are roughly equivalent, but Unix does not provide length when enumerating directories. We have to make another call to get the file length. .NET being designed for Windows, the content of what is in <samp>FileSystemInfo</samp> (and therefore matches what Windows gives back during enumeration). Unix doesn't give much more than the file name. To allow for this a number of the properties are lazy in the Unix implementation. Time stamps, length, and attributes are all in this bucket. Even the filename is lazy in that we don't convert the raw UTF-8 data to <samp>char</samp> until you access it. These details are important to know for multiple reasons:
<ol>
 	<li>Calling properties you don't strictly need can have non-trivial cost</li>
 	<li>Sitting on the struct without calling properties can give different results depending on how long you wait (notably with time stamps- we go out of our way to keep attributes constant)</li>
 	<li>Using <samp>IsDirectory</samp> and <samp>IsHidden</samp> is better than using <samp>Attributes</samp> to check those states</li>
</ol>
<h3>FileSystemEnumerator</h3>
<samp>FileSystemEnumerable</samp> is a simple <samp>IEnumerable</samp> wrapper around <samp>FileSystemEnumerator</samp>. <samp>FileSystemEnumerable</samp> is meant to be simpler and provide a model that limits the number of types via delegate usage. <samp>FileSystemEnumerator</samp> has a few more complicated options that can be used for even more advanced scenarios.

<script src="https://gist.github.com/JeremyKuhne/35183723d62ec852b53a193a3233369b.js"></script>

Using the enumerator directly you can (if desired) more easily track when directories finish and have more control over errors. As the errors are native error codes, you would need to check the platform in addition to the code to know how to respond. It is not intended to be easy or commonly needed.
<h3>FileSystemName</h3>
This helper class provides filename matching methods.

<script src="https://gist.github.com/JeremyKuhne/5b14ed5d33397a8b7108be7726efbc2f.js"></script>

Both <samp>Matches*</samp> methods allow escaping with the forward slash character <samp>'/'.</samp>

<samp>MatchesWin32Expression()</samp> is a little complicated. It matches according to <a href="https://msdn.microsoft.com/en-us/library/ff469270.aspx">[MSA-FS] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression</a>. This is the algorithm that Windows actually uses under the covers (see <a href="https://msdn.microsoft.com/en-us/library/hh551132(v=vs.85).aspx"><samp>RtlIsNameInExpression</samp></a>). If you want to match the way Win32 does you first have to call <samp>TranslateWin32Expression()</samp> to get your <samp>'*'</samp> and <samp>'?'</samp> translated to the appropriate <samp>'&gt;'</samp>, <samp>'&lt;'</samp>, and <samp>'"'</samp> characters. It is there if you want to match in the Win32 style. <samp>MatchesSimpleExpression()</samp> is the recommended style of matching. Win32 rules aren't easy to intuit.

That's the summary of the changes we've introduced in 2.1.
<h3>FAQ</h3>
<strong>Why is this so complicated?</strong>
<p style="margin-top: 0px;margin-bottom: 16px;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-size: 16px;font-style: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px">This isn't intended to be a common-use API. The existing APIs will be kept, maintained, and extended based on customer demand. We don't want to:</p>

<ol style="padding-left: 2em;margin-top: 0px;margin-bottom: 16px;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-size: 16px;font-style: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px">
 	<li>Have scenarios blocked waiting for new APIs to work their way through the system</li>
 	<li>Have to write "normal" APIs to address more corner cases</li>
</ol>
<p style="margin-top: 0px;margin-bottom: 16px;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-size: 16px;font-style: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px">In order to make this a usable extension point we have to sacrifice some usability to get the necessary characteristics. Note that what people build on this will directly impact our future designs of the standard, usability focused, APIs.</p>

<h4 style="margin-top: 24px;margin-bottom: 16px;font-size: 16px;font-weight: 600;line-height: 1.25;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-style: normal;letter-spacing: normal;text-align: start;text-indent: 0px">Why are you using Linq in your examples?</h4>
<p style="margin-top: 0px;margin-bottom: 16px;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-size: 16px;font-style: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px">For example clarity. Some of the examples above could be optimized further.</p>

<h4 style="margin-top: 24px;margin-bottom: 16px;font-size: 16px;font-weight: 600;line-height: 1.25;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-style: normal;letter-spacing: normal;text-align: start;text-indent: 0px">Why aren't you providing an<span></span><em> <code><span>X</span></code> </em>matcher?</h4>
<p style="margin-top: 0px;margin-bottom: 16px;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-size: 16px;font-style: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px">We want to only provide matchers that have broad applicability. Based on feedback we can and will consider adding new matchers in the future.</p>

<h4 style="margin-top: 24px;margin-bottom: 16px;font-size: 16px;font-weight: 600;line-height: 1.25;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-style: normal;letter-spacing: normal;text-align: start;text-indent: 0px">How do I get other platform specific data?</h4>
<p style="margin-top: 0px;margin-bottom: 16px;color: #24292e;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';font-size: 16px;font-style: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px">This is something we're investigating for future improvements. We might, for example, expose the UTF-8 data via another interface off of the entry data (or some other mechanism).</p>]]></content:encoded>
    </item>
    <item>
      <title>System.IO in .NET Core 2.1 sneak peek</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/system-io-in-net-core-2-1-sneak-peek</link>
      <pubDate>Thu, 08 Mar 2018 01:46:22 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=585</guid>
      <description><![CDATA[Now that .NET Core 2.1 Preview 1 has released it is time for a preview of what you can expect to see...]]></description>
      <content:encoded><![CDATA[Now that .NET Core 2.1 Preview 1 has <a href="https://blogs.msdn.microsoft.com/dotnet/2018/02/27/announcing-net-core-2-1-preview-1/">released </a>it is time for a preview of what you can expect to see in Preview 2 and beyond in the System.IO namespace. The 2.1 release changes are the largest changes in quite some time.
<h3>Goals</h3>
<strong>Cross platform</strong>

Code should run consistently as possible between platforms. You should also be able to successfully write code that works in mixed environments. Accessing a Unix volume from Windows should just work, for example.

<strong>Light touch</strong>

System.IO's aggressive handholding blocked a number of scenarios, including mixed environments as described above. Historically this was driven partially due to Code Access Security (CAS) in NetFX (e.g. 4.x). It was also a more plausible approach when .NET was a Windows only solution to aggressively attempt to predict OS behavior. .NET judging the validity of paths is the key example of this well-intentioned, but heavy hand. We now strive to <em>not</em> replicate or predict the outcome of OS API calls.

<strong>Performant</strong>

This is always important to us. We want to put as little overhead on your platform and enable building performant solutions.

<strong>Flexible</strong>

We don't want to have an API for every single conceivable scenario, but neither do we want to make it impossible/difficult to build solutions. Part of addressing this is just being flexible and forward-thinking in the API set in general. Another part of this can be addressed by providing extension points that allow you to build complicated solutions in a performant way without resorting to P/Invoking directly into the underlying platform.
<h3>Overview</h3>
What are you getting from this release? Here are the highlights:
<ol>
 	<li>More consistent behavior cross platform</li>
 	<li>Fixed edge cases, particularly on Windows</li>
 	<li>New <samp>Span&lt;char&gt;</samp> APIs in <samp>System.IO.Path</samp></li>
 	<li><samp>Path.Join()</samp> APIs that don't have root checking behavior like <samp>Path.Combine()</samp></li>
 	<li><samp>Path.GetFullPath()</samp> overload that avoids using the current working directory</li>
 	<li>A number of new directory enumeration options
<ol>
 	<li>Filtering out specific attributes</li>
 	<li>Simple matching behavior</li>
 	<li>Ignoring inaccessible files</li>
 	<li>Specifying buffer size (notably for Windows UNC scenarios)</li>
</ol>
</li>
 	<li>A low-level enumeration extensibility API</li>
 	<li>Significantly faster directory enumeration
<ol>
 	<li>Typically 2-4x faster on Windows (Unix 1.3x - 1.4x)</li>
 	<li>Significantly lower allocation counts (2x - 40x lower, GC collections cut 8x+)</li>
</ol>
</li>
 	<li>Faster Path APIs (<samp>GetFullPath()</samp> is now 2x as fast as .NET Core 2.0)</li>
</ol>
<h3>Key behavior changes</h3>
We've changed behavior to fix issues. Here are the key impacts:
<ul>
 	<li>Exceptions for "bad" paths are thrown when <em>used</em>, <em>not</em> when normalizing (as we can't know what is "valid" without using them)</li>
 	<li>Cross plat scenarios are no longer blocked (mounting Unix volumes/shares on Windows for one example)</li>
 	<li>Performance is significantly increased</li>
 	<li>Behavior is more consistent when running code across platforms</li>
</ul>
In more detail this means:
<ul>
 	<li>We've made matching consistent with legacy behavior on non-Windows platforms (<samp>????.txt</samp> matches the same on all platforms)</li>
 	<li>Match expressions no longer match 8.3 file names on Windows (<samp>*.htm</samp> will match only <samp>*.htm</samp>, <strong>not</strong> <samp>*.html</samp>, <samp>*.htmz</samp> <em>if</em> the volume 8.3 generation on)</li>
 	<li>We've fixed enumeration of unusual Windows files - you can now get *Info classes out successfully and use the methods on files that end in spaces, periods</li>
 	<li>We do very little validation of paths up front as there is very little we can accurately predict (unblocking numerous xplat and some existing Windows scenarios)</li>
 	<li>We only check for embedded nulls, no other chars are rejected, including wildcards (as nulls are never supported and OS APIs almost universally take null terminated strings)
<ul>
 	<li>We don't check for "proper" colon placement</li>
 	<li>We don't check for segment length or total path length</li>
 	<li>We don't check for "proper" UNCs</li>
 	<li>We still throw for null or empty paths on all platforms or paths of all spaces on Windows (as they throw from the Win32 GetFullPathName)</li>
</ul>
</li>
 	<li>We don't trim leading spaces on any paths on Windows anymore (we did for some, not others)</li>
 	<li>We don't trim whitespace characters from the end of paths on Windows (such as nbsp)</li>
 	<li><samp>GetPathRoot</samp>, <samp>GetDirectoryName</samp>, etc. don't throw for empty anymore, they return null (like they do for null).</li>
 	<li><samp>GetPathRoot</samp> now works consistently with various Windows prefixes (e.g. <samp>\\?\</samp>, <samp>\\.\</samp>)</li>
</ul>
<h3>New System.IO.Path APIs</h3>
The majority of what we have here are new <samp>ReadOnlySpan&lt;char&gt;</samp> overloads, which allow you to avoid unnecessary string allocations. Spans are a key new feature in .NET 2.1. You can pass strings as spans using the <samp>.AsSpan()</samp> extension (there is an implicit conversion as well). <samp>ReadOnlySpan&lt;char&gt;</samp> has a number of extensions that allow you to evaluate it as you would a string.

<samp>Join()</samp> APIs allow putting path segments together without analysis of segment rooting. <samp>Combine("C:\Foo\", "\Bar")</samp> gives you <samp>"\Bar"</samp>. <samp>Join</samp> gives you <samp>"C:\Foo\Bar"</samp>.

<samp>Path.GetFullPath(path, basePath)</samp> is an important addition. Normalizing paths that aren't fully qualified (e.g. relative to the current directory) is dangerous and discouraged. The reason is that the current directory is a process-wide setting. Getting into a state where a separate thread unexpectedly changes the working directory is common enough that you should make every attempt to <em>not</em> use the existing GetFullPath().

<script src="https://gist.github.com/JeremyKuhne/19fcbe193661a6772d6d6643b6be031a.js"></script>
<h3>New EnumerationOptions</h3>
There have been numerous asks for directory enumeration options over the years. To fulfill some of those requests and allow addressing more we're introducing the EnumerationOptions class. The existing Directory and DirectoryInfo enumeration methods now have overloads that take this new class.

This class has some defaults that are different than historical behavior:
<ol>
 	<li>Matching is simple- <samp>'?'</samp> is always one character, <samp>'*'</samp> is always 0+, <samp>"*.*"</samp> is any filename with a period</li>
 	<li>Hidden and system files are skipped by default- typically one doesn't want the <samp>.vs</samp>, <samp>.git</samp>, <samp>$RECYCLE.BIN</samp>, <samp>Thumbs.db</samp> etc. folders in results.</li>
</ol>
You can, of course, choose any setting you want.

<script src="https://gist.github.com/JeremyKuhne/42b951b427e3db791e3e965f5054dae2.js"></script>
<h3>New enumeration extensibility model</h3>
Those options not enough? Now you can write your own fast, low level enumerators. Want your own matching algorithm? Want to total file sizes? Want to match all files with a set of extensions? Almost anything is possible with the new API that live in System.IO.Enumeration. It is a large topic, so I'll address it in the <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2018/03/09/custom-directory-enumeration-in-net-core-2-1/">next post</a>.
<h3>FAQ</h3>
<strong>What exceptions do I get from bad paths now?</strong>

Whatever the OS tells us, we'll tell you. This will always be some sort of <samp>IOException</samp> for a bad path. Sometimes it might be a <samp>File/DirectoryNotFound</samp>. The key thing to remember is that you get exceptions when you try to use the path. <samp>GetFullPath()</samp> doesn't throw for these as it has no practical way of checking.

<strong>What if I still want to check invalid characters</strong><b>?</b>

You can do this manually using <samp>GetInvalidPathChars()</samp>. It isn't recommended as it isn't always correct on any platform. You may have NTFS/FAT volumes mounted in Unix or vice-versa.

<strong>Where did the speed improvements come from?</strong>

Primarily from reducing allocations. Keeping work on the stack and out of the heap can have a dramatic impact on large sets. Some wins come from smarter use of available OS APIs. A chunk comes from not validating paths on every single API call.

<strong>When does AttributesToSkip get applied?</strong>

First thing. One effect of this is that filtering out <samp>FileAttributes.Directory</samp> makes the <samp>RecurseSubdirectories</samp> option meaningless.

<strong>What about other file matching types?</strong>

We definitely want to add more in the future. Things like globstar (<samp>**</samp>), POSIX pattern matching notation (glob), possibly regex. With the extensibility APIs writing a custom matcher is easy. If you're passionate about any of these we're always open to contributions.

<strong>Why did you change enumeration defaults?</strong>

Note that we <em>only</em> changed them when you use the new <samp>EnumerationOptions</samp> class. Existing APIs should behave as they did (modulo the matching consistency fixes mentioned in the post). We picked new defaults based on OS defaults (shell &amp; command line) and what one would expect when enumerating end-user files (e.g. to present to users). These obviously won't be right for all scenarios, but changing the settings is easy.

<strong>What about the more obscure Windows matching characters?</strong>

<samp>'&lt;'</samp>, <samp>'&gt;'</samp>, and <samp>'"'</samp> were unblocked in 2.0. They're still supported, but only on Windows through the normal APIs. You can, if you want, use them on Unix if you use the extensibility points described in the next post.]]></content:encoded>
    </item>
    <item>
      <title>Wildcards in Windows</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/wildcards-in-windows</link>
      <pubDate>Sun, 04 Jun 2017 21:15:34 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=545</guid>
      <description><![CDATA[I put forth the challenge in my last post about how to match files that start, end, or simply have a...]]></description>
      <content:encoded><![CDATA[I put forth the challenge in <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2017/05/31/wildcard-challenge/">my last post</a> about how to match files that start, end, or simply have a period in them. It isn't easy to do.

Wildcards in paths seem simple at first. You have <samp>'?'</samp> to match any single character and <samp>'*'</samp> to match zero or more of any characters.

Matching in reality doesn't exactly match up. <samp>'*'</samp> gives you all files. <samp>'?'</samp> gives you all files that are just one character. <samp>'*a*'</samp> gives you all files that have an <samp>'a'</samp> in them. <samp>'*_*'</samp> gives you all files that have an underscore in them. <samp>'*.*'</samp> gives you ... all files.

The seemingly odd behavior of matching dates back to <a href="https://blogs.msdn.microsoft.com/oldnewthing/20071217-00/?p=24143/">DOS days</a>. Every file was in 8.3 form: 8 characters for the name, a period, and a 3 character file extension. You couldn't use a period in the filename or extension- it was <em>always</em> the separator for the two filename components. (The period wasn't even stored on disk.)
<p class="aside">MS-DOS was based on QDOS (later 86-DOS), which was written by Tim Patterson for Seattle Computer Products for their 8086 computer kit. It was designed to be compatible with the dominant microcomputer OS of the late 70s, CP/M. Both QDOS and CP/M had 8.3 filenames and used similar wildcard matching with <samp>?</samp> and <samp>*</samp>. CP/M was inspired primarily by DEC OSes, which had the same style filenames and wildcard matching. (Most DEC OSes had 6.3 filenames, and also used the colon '<samp>:</samp>' to specify devices, akin to '<samp>C:</samp>'.)</p>
With the advent of 32 bit Windows (Windows 95 and NT), 8.3 filenames were no longer a limitation. You could now have filenames that were up to 255 characters, and the period was now a legitimate character. After 25 years or so of <samp>'*.*'</samp>, keeping similar semantics made a lot of sense. Here are some of the common patterns in DOS:
<table>
<tbody>
<tr>
<th>Pattern</th>
<th>Meaning</th>
</tr>
<tr>
<td><samp>*.*</samp></td>
<td>All file names, all extensions (all files).</td>
</tr>
<tr>
<td><samp>*.</samp></td>
<td>All file names without extensions.</td>
</tr>
<tr>
<td><samp>foo*.*</samp></td>
<td>All files beginning with "foo".</td>
</tr>
<tr>
<td><samp>foo??.*</samp></td>
<td>All files beginning with "foo" and up to two additional characters.</td>
</tr>
</tbody>
</table>
The real rules were subtle and had some "surprising" behaviors that were not carried forward to Win32. Raymond Chen describes the algorithm in "<a href="https://blogs.msdn.microsoft.com/oldnewthing/20071217-00/?p=24143/">How did wildcards work in MS-DOS?</a>".

So how <em>exactly</em> do wildcards work now? The patterns mentioned above work as expected, but how? It obviously isn't exactly correct that <samp>'?'</samp> matched any single character and <samp>'*'</samp> to match zero or more of any characters... The answer lies in that there are actually <strong>five</strong> wildcards in Windows:
<table>
<tbody>
<tr>
<th>Wildcard</th>
<th>Meaning</th>
</tr>
<tr>
<td><samp>*</samp></td>
<td>Zero or more characters.</td>
</tr>
<tr>
<td><samp>?</samp></td>
<td>Exactly one character.</td>
</tr>
<tr>
<td><samp>&lt;</samp></td>
<td>Matches zero or more characters until encountering and matching the final period in the name. (DOS_STAR)</td>
</tr>
<tr>
<td><samp>&gt;</samp></td>
<td>Matches any single character, or zero if to the left of a period or the end of the string- or contiguous to other <samp>&gt;</samp> that are in said position. (DOS_QM)</td>
</tr>
<tr>
<td><samp>&quot;</samp></td>
<td>Matches a period or zero characters at the end of the string. (DOS_DOT)</td>
</tr>
</tbody>
</table>
If these are the rules, why don't they work that way? The answer is that Win32 implicitly changes your wildcards. This is the another part to the mystery of wildcards. The rules are as follows:
<ul>
 	<li>All '<samp>?</samp>' are changed to '<samp>&gt;</samp>'.</li>
 	<li>All '<samp>.</samp>' followed by '<samp>?</samp>' or '<samp>*</samp>' are changed to '<samp>&quot;</samp>'.</li>
 	<li>A path ending in '<samp>*</samp>' that had a final period <em>before</em> normalizing is changed to '<samp>&lt;</samp>'.</li>
</ul>
The last rule brings up the last piece of the wildcard puzzle. As described in my <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/04/21/path-normalization/">previous posts</a>, path normalization eats trailing periods and spaces. This can make it difficult to search for filenames with trailing spaces/periods.

Now that we have the details of wildcard matching the challenges in <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2017/05/31/wildcard-challenge/">my last post</a> can be answered.
<h4>List files ending with a space</h4>
You need to skip normalization for this to work. <kbd>dir "\\?\C:\* "</kbd> will give you all files that end with a space in "<samp>C:\</samp>".
<h4>List files starting with a period</h4>
This is actually pretty simple. <kbd>dir .*</kbd> will give you all files that start with a period in the current directory.
<h4>List files with a period</h4>
This involves using the "DOS" wildcards directly (which need to be escaped at the command line). <kbd>dir *.^&lt;</kbd> will give you all files that have a period in the current directory. "<samp>*.&lt;</samp>" is necessary as, per the rules, "<samp>*.*</samp>" would become "<samp>*&quot;*</samp>" which is equivalent to "<samp>*</samp>".
<h4>List files ending with a period</h4>
You need to skip normalization for this to work. <kbd>dir \\?\C:\*.</kbd> will give you all files that end with a period in "<samp>C:\</samp>".
<h3>APIs in play</h3>
Searching for files always goes through one of the <samp><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa364419(v=vs.85).aspx">FindFirstFile</a></samp> APIs. <samp>FindFirstFile</samp> will normalize the path, cutting it into the directory portion of the path and the filename. The filename wildcards are munged as explained above. <samp>FindFirstFile</samp> opens a file handle on the directory and calls <samp><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff556633.aspx">NtQueryDirectoryFile</a></samp> with the altered filename. (Full details of the API are in the kernel mode version <samp><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff567047.aspx">ZwQueryDirectoryFile</a></samp>.)

When the filesystem driver responds to the query it will use <samp><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff546850.aspx">FsRtlIsNameInExpression</a></samp> to do it's matching. <samp><a href="https://msdn.microsoft.com/en-us/library/hh551132.aspx">RtlIsNameInExpression</a></samp> is the user mode version of this API. (Note that the documentation can be a little misleading. When you do a case-insensitive search <em>and</em> don't provide a translation table, the name is converted to uppercase. The expression (pattern) is not- you have to do this manually. <samp><a href="https://msdn.microsoft.com/en-us/library/windows/hardware/ff563005.aspx">RtlUpcaseUnicodeString</a></samp> is the Win32 API for this.)

If you really want to use "<samp>*</samp>" and "<samp>?</samp>" you could potentially call <samp>NtQueryDirectoryFile</samp> directly. You won't get your existing search string changed, but all five wildcards are processed, of course.]]></content:encoded>
    </item>
    <item>
      <title>Wildcard challenge</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/wildcard-challenge</link>
      <pubDate>Wed, 31 May 2017 05:38:15 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=555</guid>
      <description><![CDATA[Finding files with spaces from a command prompt might not be immediately obvious. Using quotes is...]]></description>
      <content:encoded><![CDATA[Finding files with spaces from a command prompt might not be immediately obvious. <a href="https://blogs.msdn.microsoft.com/oldnewthing/20061205-00/?p=28833">Using quotes is the answer</a><span>.</span>
<ol>
 	<li>List all files with a space: <strong><samp>dir "* *"</samp></strong></li>
 	<li>List all files that start with a space: <strong><samp>dir " *"</samp></strong></li>
 	<li>List all files that <em>end</em> with a space: <em><samp>???</samp></em></li>
</ol>
#3 is a bit more challenging. Normalization has something to do with the answer.

The <em>real</em> challenge is how do you find files with <em>periods</em>??
<ol>
 	<li>List all files with a period: <em><samp>???</samp></em></li>
 	<li>List all files that start with a period: <em><samp>???</samp></em></li>
 	<li>List all files that <em>end</em> with a period: <em><samp>???</samp></em></li>
</ol>
Can they all even be done? If not, why? If you have an answer, why does it work?

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Creator's Update, .NET 4.7 and long paths</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/creators-update-net-4-7-and-long-paths</link>
      <pubDate>Wed, 31 May 2017 00:56:51 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=535</guid>
      <description><![CDATA[Most notable bit is CMD supports long paths now. You still need to enable the long path policy as it...]]></description>
      <content:encoded><![CDATA[Most notable bit is CMD supports long paths now. You still need to enable the long path policy as it isn't on by default.

.NET 4.7 had some minor tweaks. It now allows using device syntax (\\?\) with FileIOPermissions as long as you are running in full trust. This should allow you to use \\?\ paths everywhere (classes that asserted permissions outside of mscorlib didn't work in 4.6.2).

I also fixed a <a href="https://support.microsoft.com/en-us/help/3181958/path.getdirectoryname-and-path.getpathroot-don-t-work-with-uris-when-you-target-the-.net-framework-4.6.2">bug on my part</a> in 4.7. (doh)]]></content:encoded>
    </item>
    <item>
      <title>.NET 4.6.2 and long paths on Windows 10</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/net-4-6-2-and-long-paths-on-windows-10</link>
      <pubDate>Sat, 30 Jul 2016 01:21:22 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=516</guid>
      <description><![CDATA[The Windows 10 Anniversary update is almost out the door. .NET 4.6.2 is in the update (as we've...]]></description>
      <content:encoded><![CDATA[The Windows 10 Anniversary update is almost out the <a href="https://blogs.windows.com/windowsexperience/2016/06/29/windows-10-anniversary-update-available-august-2/">door</a>. .NET 4.6.2 is in the update (as we've looked at in the past few posts). I've talked a bit about what we've done in 4.6.2 around <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/06/21/more-on-new-net-path-handling/">paths</a>, and how that is targeted at both allowing access to previously inaccessible paths and opens up the door for long paths when the OS has support. Well, as people have <a href="http://betanews.com/2016/05/29/long-paths-windows-10/">discovered</a>, Windows 10 now has started to open up support. In this post I'll talk about how to enable that support.
<h2>Enabling Win32 Long Path Support</h2>
Long paths aren't enabled by default yet. You need to set a policy to enable the support. To do this you want to "<samp>Edit group policy</samp>" in the Start search bar or run "<samp>gpedit.msc</samp>" from the Run command (<samp>Windows-R</samp>).

In the Local Group Policy Editor navigate to "<samp>Local Computer Policy: Computer Configuration: Administrative Templates: All Settings</samp>". In this location you can find "<samp>Enable Win32 long paths</samp>".

[caption id="attachment_525" align="alignnone" width="754"]<a href="https://msdnshared.blob.core.windows.net/media/2016/07/LongPathPolicy.png"><img width="754" height="530" class="size-full wp-image-525" alt="Enabling Win32 long paths in the policy editor." src="https://msdnshared.blob.core.windows.net/media/2016/07/LongPathPolicy.png" /></a> Enabling Win32 long paths in the policy editor.[/caption]

After you've turned this on you can fire up a new instance of PowerShell and free yourself from the constraints of <samp>MAX_PATH</samp>! The key File and Directory Management APIs respect this and now allow you to skip the check for <samp>MAX_PATH</samp> without having to resort to using "<samp>\\?\</samp>" (look back to my earlier posts on <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/04/21/path-format-overview/">path formats</a> to understand how this works). This is also possible as PowerShell has opted into the new .NET path support (being that it is a .NET application).

If you look carefully at the description in the setting you'll see "<samp>Enabling Win32 long paths will allow <strong>manifested</strong> win32 applications...</samp>". That's the <strong>second gate</strong> to getting support- your app must have a specific manifest setting. You can see what this is by opening <samp>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</samp> in Visual Studio or some other manifest viewer. Doing so you'll see the following section in it's manifest:
<pre>&lt;application xmlns="urn:schemas-microsoft-com:asm.v3"&gt;
  &lt;windowsSettings&gt;
    &lt;longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings"&gt;true&lt;/longPathAware&gt;
  &lt;/windowsSettings&gt;
&lt;/application&gt;
</pre>
These two gates will get you the native (Win32) support for long paths. In a managed app you'll also need the new behavior in .NET. The next section covers this.
<h2>Configuring a Simple Long Path .NET Console App</h2>
This example uses a new C# Console Application in Visual Studio 2015.

The first thing to do after creating a new console app is edit the App.Config file and add the following after the <samp>&lt;startup&gt;</samp> end tag:
<pre>&lt;runtime&gt;
  &lt;AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" /&gt;
&lt;/runtime&gt;</pre>
If you have the 4.6.2 Targeting Pack installed (from the <a href="https://www.microsoft.com/en-us/download/details.aspx?id=53321">4.6.2 Developer Pack</a>) you can alternatively select 4.6.2 as your target framework in the project properties instead of using the app.config setting. The defaults for these two values are <strong>true</strong> if the target framework is 4.6.1 or earlier.

The second thing to do is add the Application Manifest File item to your project. After doing so add the <samp>windowsSettings</samp> block I shared above. In the default template there is already a commented-out section for <samp>windowsSettings</samp>, you can uncomment this and add this specific <samp>longPathAware</samp> setting.

Here is a sample block to add to your Main() method to test it out:
<pre>string reallyLongDirectory = @"C:\Test\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
reallyLongDirectory = reallyLongDirectory + @"\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
reallyLongDirectory = reallyLongDirectory + @"\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

Console.WriteLine($"Creating a directory that is {reallyLongDirectory.Length} characters long");
Directory.CreateDirectory(reallyLongDirectory);</pre>
You can open up PowerShell and go and look at the directory you created! Yayyyyyy!

This is the start of what has been a very long journey to remove MAX_PATH constraints. There is still much to do, but now the door is <em>finally</em> open. The rest can and will come- keep your feedback coming in to keep us on track!

The Windows support is documented on <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx">MSDN</a>. APIs that aren't listed may work- if the API took \\?\ in the past it will likely support the new behavior.

<em>Note that in this initial release CMD doesn't support long paths. The Shell doesn't add support either, but previously had limited support utilizing 8.3 filename trickery. I'll leave it to the Windows team for any further details.</em>]]></content:encoded>
    </item>
    <item>
      <title>More on new .NET path handling</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/more-on-new-net-path-handling</link>
      <pubDate>Tue, 21 Jun 2016 23:39:20 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=506</guid>
      <description><![CDATA[In my prior post I talked briefly about the new path handling in .NET 4.6.2. In the latest drop...]]></description>
      <content:encoded><![CDATA[In my prior <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/06/09/new-net-path-handling-sneak-peek/">post</a> I talked briefly about the new path handling in .NET 4.6.2. In the latest drop (<a href="https://blogs.windows.com/windowsexperience/2016/06/16/announcing-windows-10-insider-preview-build-14367-for-pc-and-mobile/">14367</a>) PowerShell opts into <em>both</em> of the new behaviors so you can easily play around with the changes.

There are two basic changes that can be controlled via two compatibility switches. The changes both originated in <a href="https://github.com/dotnet/corefx">CoreFX</a> so you can get a more detailed look if you so choose. I'm going to talk about these this week on <a href="https://www.youtube.com/watch?v=ZppqEMegCAA">On .NET</a>, so bring your questions.
<h3>Normalization Changes</h3>
The first change is that we now try to defer to the OS to normalize paths. Trying to emulate what the OS does led to some discrepancies- one notable one being that you couldn't do anything with directories that end in a space. You can create directories with a space at the end from the <samp>CMD</samp> prompt, but they were impossible to do anything with in .NET. Refer back to my post on <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/04/21/path-normalization/">normalization</a> to see a bit more about what is/isn't possible in Windows.

The second change is that we allow better access to DOS <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/04/21/path-format-overview/">device</a> paths. This includes both the normalized (<samp>\\.\</samp>) and non-normalized (<samp>\\?\</samp>) syntaxes. These were poorly documented and subsequently poorly understood. Handling was spotty and inconsistent. Getting at paths that were possible using non-normalized syntax (such as <samp>\\?\C:\foo.</samp>) used to be impossible in .NET.

Both of the DOS device path syntaxes skip most character validity checks. Why? Those checks were wrong and essentially impossible to get correct. Named pipes, for example, can use many characters you can't use in a "normal" NTFS path (and do, Nvidia creates a pipe like this on my machine). This sort of validation is better left to the OS and the various drivers involved, so we do.

The extended DOS device syntax will only work for core APIs that live in mscorlib if you're in full trust. FileIOPermissions historically is the class responsible for kicking <samp>\\?\</samp> paths and still is. Comparing extended paths is too costly to do in <samp>FileIOPermissions</samp> (partially because paths don't have to exist, which makes the logic crazy). For this release the internal usages in mscorlib have a special out when we're running full trust. This should cover the vast majority of usages. I'm looking into expanding this to all usages of FileIOPermissions in full trust in a future .NET. (Note that there are no such limitations for CoreFX as there is no limited trust model.)

Normalization changes are controlled via the <samp>UseLegacyPathHandling</samp> switch, which is off by default if you target 4.6.2 or higher (the semantics here are part of the AppContext design- you opt into backwardly compatible behavior on newer Framework versions).
<h3>Long Path Changes</h3>
The key driver in re-evaluating the normalization was the need to support long paths (paths over <samp>MAX_PATH</samp>, or 260 characters). The old logic didn't scale and prevented usage of the current "long path" solution on Windows, extended DOS device paths (<samp>\\?\</samp>).

In 4.6.2 we will no longer throw <samp>PathTooLongException</samp> if we see a path that is <samp>&gt;= MAX_PATH</samp>. If the OS doesn't like it we'll surface whatever the OS returns as an error (which may be PathTooLong), but we won't second guess what the OS will do. This enables you to use extended long paths and, if the OS <a href="http://betanews.com/2016/05/29/long-paths-windows-10/">would let you</a>, regular long paths. *cough* :)

(Note that in many cases the OS will return DirectoryNotFound for paths that are too long. The primary case is with creating files. We don't have a way to programmatically check whether paths are actually too long so we can't translate DirectoryNotFound into PathTooLong. We're looking at updating the exception text in the future to say it "may also be caused by a path that is too long" where such a thing is possible.)

In CoreFX, .NET will put the extended syntax on for you when calling Windows APIs. This allows you to use long paths without any extra thought or new OS support (if it should ever arrive *cough* *cough*). This implicit handling isn't done in 4.6.2 as it was to costly to fit in the schedule (it is a <em>much</em> more difficult task to get this implicit support in the desktop code as opposed to CoreFX).

The long path changes are controlled via the <samp>BlockLongPaths</samp> switch, which again is off by default if you target 4.6.2 or higher.
<h3>Config File Setting</h3>
If you target 4.6.2 this isn't necessary, but if you want to enable the behavior for existing code, here is config file snippet you need to use.
<pre>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration&gt;
  &lt;runtime&gt;
    &lt;AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" /&gt;
  &lt;/runtime&gt;
&lt;/configuration&gt;</pre>]]></content:encoded>
    </item>
    <item>
      <title>New .NET path handling sneak peek</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/new-net-path-handling-sneak-peek</link>
      <pubDate>Thu, 09 Jun 2016 05:25:08 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=496</guid>
      <description><![CDATA[As mentioned I'm going to do the On .NET show in a couple weeks to talk about path changes in .NET....]]></description>
      <content:encoded><![CDATA[As mentioned I'm going to do the <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/06/02/long-paths-in-net/">On .NET</a> show in a couple weeks to talk about path changes in .NET. In the meantime, a little bit of fun for you if you've got the latest (<a href="https://blogs.windows.com/windowsexperience/2016/06/08/announcing-windows-10-insider-preview-build-14361/">14361</a>) fast ring build for Windows 10 Anniversary Update...

<mark>UPDATE:</mark> In the latest drop (<a href="https://blogs.windows.com/windowsexperience/2016/06/16/announcing-windows-10-insider-preview-build-14367-for-pc-and-mobile/">14367</a>) PowerShell opts into the new behaviors- the following config file isn't necessary.

Drop a file called <samp>powershell.exe.config</samp> in <samp>C:\Windows\System32\WindowsPowerShell\v1.0</samp> with the following contents to opt in to one of the new 4.6.2 features (as PS doesn't target 4.6.2):
<pre>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration&gt;
  &lt;runtime&gt;
    &lt;AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false" /&gt;
  &lt;/runtime&gt;
&lt;/configuration&gt;
</pre>
Now start up PowerShell and create yourself a <samp>C:\foo directory</samp> so you can try a few things.

&nbsp;

Make yourself a <samp>foo</samp> file:
<kbd>PS C:\foo&gt; echo footext &gt; foo</kbd>

And a <samp>bar</samp> file:
<kbd>PS C:\foo&gt; echo <samp>bartext</samp> &gt; bar</kbd>

Copy <samp>foo</samp> to <samp>bar:foo</samp>:
<kbd>PS C:\foo&gt; copy foo \\?\C:\foo\bar:foo</kbd>

Take a look at what we've got:
<kbd>PS C:\foo&gt; dir \\?\C:\foo</kbd>

Now take a closer look:
<kbd>PS C:\foo&gt; type bar</kbd>
<kbd>PS C:\foo&gt; type -LiteralPath \\?\C:\foo\bar:foo</kbd>
I'll leave it to you to play around a bit more with this. Look at my prior <a href="https://blogs.msdn.microsoft.com/jeremykuhne/2016/04/21/path-format-overview/">posts</a> on path handling to clarify what is going on here and try and give me some of your own cool examples of what you can do. :)]]></content:encoded>
    </item>
    <item>
      <title>Using MSBuild properties in T4 templates</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/using-msbuild-properties-in-t4-templates</link>
      <pubDate>Tue, 07 Jun 2016 01:09:21 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=495</guid>
      <description><![CDATA[The Problem
Text Templates in VS are cool, but they have some rough edges. One in particular is...]]></description>
      <content:encoded><![CDATA[<h3>The Problem</h3>
Text Templates in VS are cool, but they have some rough edges. One in particular is getting at project properties from your templates.

One of the biggest problems is that the generator for the project build and the generator that runs inside VS are different. The project build generator will allow you to define your own parameters to send to the build task, but the VS generator won't read them. The VS generator will let you look at only 4 things:
<ol>
	<li>"<samp>namespaceHint</samp>"</li>
	<li>"<samp>projects</samp>" (returns a vertical bar separated list of projects)</li>
	<li>"<samp>projectDefaultNamespace</samp>"</li>
	<li>"<samp><em>projectName</em>:OutputPath</samp>" (where <em>projectName</em> is the name of the project)</li>
</ol>
While you <em>could</em> match these names and values in your MSBuild project files it's pretty limiting. It's most unfortunate that the VS generator doesn't pick up <samp>&lt;T4ParameterValues&gt;</samp>.
<h3>A Solution</h3>
Utilizing a little-known ability to run arbitrary MSBuild tasks as a custom tool you can unify the behavior on the generator the project build uses. You'll need to make a small tweak to your project file to set this up.
<ol>
	<li>Edit your .cs/.vbproj and include the CustomT4.targets at the <em>end</em> of the file.</li>
	<li>Reload your project.</li>
	<li>Change the "Custom Tool" property from "<samp>TextTemplatingFileGenerator</samp>" to "<samp>MSBuild:TransformAll</samp>".</li>
	<li>Change <samp>hostSpecific="false"</samp> to <samp>"true"</samp> in the <samp>&lt;#@template&gt;</samp> directive.</li>
	<li>Use <samp>this.Host.ResolveParameterValue(".", ".", "TargetPath")</samp> to get at the <samp>TargetPath</samp> property.</li>
</ol>
The simple test template looks like the following:
<pre>&lt;#@ template debug="false" hostspecific="true" language="C#" #&gt;
&lt;#@ output extension=".txt" #&gt;
Test "&lt;#= this.Host.ResolveParameterValue(".", ".", "TargetPath") #&gt;"
</pre>
And here is the target file with a number of properties you're likely to want.
<script src="https://gist.github.com/JeremyKuhne/a35615d008259bef144139c8e0628fb4.js"></script>
<h3>Notes</h3>
The first two arguments to ResolveParameterValue() are meaningless, but can <em>not</em> be empty strings despite the documentation. I decided to use period because it's unobtrusive.]]></content:encoded>
    </item>
    <item>
      <title>VS Background Builds</title>
      <link>https://docs.microsoft.com/archive/blogs/jeremykuhne/vs-background-builds</link>
      <pubDate>Mon, 06 Jun 2016 05:18:02 GMT</pubDate>
      <dc:creator><![CDATA[JeremyKuhne]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jeremykuhne/?p=475</guid>
      <description><![CDATA[Two MSBuild related things that I keep losing track of every few years that are incredibly hard to...]]></description>
      <content:encoded><![CDATA[Two MSBuild related things that I keep losing track of every few years that are incredibly hard to discover.
<h3>Logging Background Builds</h3>
Visual Studio does a number of background (or "Design Time") builds on your behalf. They don't log anywhere by default. If you want to look at what is going on you need to "<samp>set TRACEDESIGNTIME=true</samp>" in your environment and launch VS. This will dump diagnostic builds to your "<samp>%temp%</samp>" folder in the form of "<samp><em>ProjectName</em>_<em>TargetName</em>_<em>unique</em>.designtime.log</samp>".
<h3>Using a Build Task as a Custom Tool</h3>
Finding the documentation for Custom Tool is hard enough, let alone the fact you can invoke a specified MSBuild task. Set the Custom Tool property to "<samp>MSBuild:<em>targetName</em></samp>" and a background build will fire whenever the file changes.

<a href="https://msdnshared.blob.core.windows.net/media/2016/06/CustomTool.png"><img class="alignnone size-full wp-image-485" src="https://msdnshared.blob.core.windows.net/media/2016/06/CustomTool.png" alt="CustomTool" width="418" height="210" /></a>

You'll need to turn on the background build logging as described above to see what is going on.

One last related note: <a href="https://msdn.microsoft.com/en-us/library/bb166817.aspx">IVSSingleFileCodeGenerator</a> is the normal interface involved for Custom Tools.]]></content:encoded>
    </item>
  </channel>
</rss>