While working on IE7 application compatibility, we’ve seen many cases of interesting and strange invalid file URIs. I believe a substantial amount of responsibility for the confusion over file URIs lies with the deprecated urlmon.dll function CreateURLMoniker. This function is used by Windows application developers mainly to convert a string URI into an object that can be used to obtain the data represented by the URI. CreateURLMoniker does a couple of horrible things to file URIs that if misused can lead to security bugs. For those application developers who have used this function in the past allow me to describe what’s wrong with CreateURLMoniker and what to use instead.
If you’re not a Windows application developer or you’re not interested in the details and don’t plan on reading any further here is the solution up front: Use CreateURLMonikerEx with the flag URL_MK_UNIFORM instead of CreateURLMoniker to avoid problems with file URIs. The problems with CreateURLMoniker were discovered sometime ago and this flag was introduced to allow people to switch to a valid URI parser that will do the correct thing with file URIs. We couldn’t switch to using the valid URI parser without breaking a huge number of applications that depend on this functionality.
Additionally, if what you’d like to do is convert between a file URI and Windows file path, the shlwapi.dll functions PathCreateFromUrl and UrlCreateFromPath will do this correctly.
The first problem concerns the IMoniker output of CreateURLMoniker. A call to IMoniker::GetDisplayName will produce a string containing an invalid file URI. It will be in the form that Zeke named Legacy File URI and described on his blog. This form cannot be parsed with a general URI parser and as such may not be compatible with some APIs.
The second problem concerns the input to CreateURLMoniker. CreateURLMoniker will decode any percent-encoded octet (except ‘%00’) in a file URI or Windows file path provided as input. This means that the URI you get out of CreateURLMoniker in IMoniker form may not necessarily be equivalent to the URI provided. As noted in the URI standard you can’t decode just any percent-encoded octet and expect to get an equivalent URI back. If that were the case there wouldn’t be any point to percent-encoding in URIs.
Since CreateURLMoniker will decode ‘%25’ to its corresponding ‘%’ the process is not idempotent. This means that applying CreateURLMoniker to a URI again and again may produce a different URI each time.
For example given the following Windows file path, the corresponding correct file URI, and the output from CreateURLMoniker follow:
Original Path: C:\Documents and Settings\davris\Project100%28years.xsl Correct URI: file:///C:/Documents%20and%20Settings/davris/Project100%2528years.xsl CreateURLMoniker Result: file://C:\Documents and Settings\davris\Project100(years.xsl
Note that the result from CreateURLMoniker identifies a file named “Project100(years.xsl” rather than the intended file name “Project100%28years.xsl”.
As noted above CreateURLMoniker is not idempotent. For example, starting with the following Windows file path and passing each resulting string back through CreateURLMoniker gives the following sequence of results:
Windows file path: C:\foo%25252544.txtCreateURLMoniker call 1: file://C:\foo%252544.txtCreateURLMoniker call 2: file://C:\foo%2544.txtCreateURLMoniker call 3: file://C:\foo%44.txtCreateURLMoniker call 4: file://C:\fooD.txt
This can lead to security problems in which one portion of a system believes its working with one URI while another portion of the system that has run its URI through CreateURLMoniker a different number of times believes its working on a different URI.
In IE7 we still cannot change CreateURLMoniker to use proper file URI parsing for application compatibility reasons. However, we decided to make a change to help with the idempotence problem: CreateURLMoniker will no longer decode ‘%25’ to ‘%’. This means in IE7, while CreateURLMoniker will still give back an IMoniker that may not be equivalent to the input URI the CreateURLMoniker process won’t be able to produce a new URI after every CreateURLMoniker call as seen in the example above. This is a change in behavior from IE6 and it is noted in the application compatibility logging.
However, this doesn’t address all problems of CreateURLMoniker. To reiterate, if you need an URL Moniker please use the function CreateURLMonikerEx with the flag URL_MK_UNIFORM.
We have updated the MSDN documentation to mark CreateURLMoniker as deprecated and to include the solution described here.
Dave Risney Software Design Engineer