3

I have seen similar questions (e.g. Encode/Decode URLs in C++). But, for me:

CString strURL;
DWORD dwSize = _MAX_PATH;
if (InternetCanonicalizeUrl(strFile, strURL.GetBuffer(_MAX_PATH), &dwSize, ICU_BROWSER_MODE))
{
    // still has backslash
    AfxMessageBox(strURL);
}
strURL.ReleaseBuffer();

strURL = strFile;
strURL.Replace(L"\\", L"/");
strURL = L"file:///" + strURL;
AfxMessageBox(strURL);

Using InternetCanonicalizeUrl did not work:

  1. The prefix was file:// and not file:///.
  2. The \ was not replaced with /.

I did it manually and my version of the URL works with my subsequent WebView2 function. To clarify, the path itself was built with ::GetTempPath() and/or ::GetTempFileName().

Why did the built-in API call not do what I needed?

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164

1 Answers1

3

Why did the built-in API call not do what I needed?

The best answer I can give to this "Why?" part of your question is that the "WinInet" library component of the WinAPI uses (or, at least, is based on) Internet Explorer internally … and we all know how dodgy and non-conformant IE can be.

However, the documentation for the InternetCanonicalizeUrl function does actually suggest (albeit cryptically) an alternative if you want a more complete/compliant result:

In Internet Explorer 4.0 and later, InternetCanonicalizeUrl always functions as if the ICU_BROWSER_MODE flag is set. Client applications that must canonicalize the entire URL should use either CoInternetParseUrl (with the action PARSE_CANONICALIZE and the flag URL_ESCAPE_UNSAFE) or UrlCanonicalize.

I experimented with the latter alternative (it seemed the simpler of the two) and found a relatively trivial fix for your issue:

//  if (InternetCanonicalizeUrl(strFile, strURL.GetBuffer(_MAX_PATH), &dwSize, ICU_BROWSER_MODE))
    if (UrlCanonicalize(strFile, strURL.GetBuffer(_MAX_PATH), &dwSize, 0) == S_OK)
    {
        AfxMessageBox(strURL);
    }
    strURL.ReleaseBuffer();

In the test I ran (using the path from GetTempPath()), this gives the full file:/// prefix and replaces all backslashes with forward slashes.

(You will need to #include <shlwapi.h> somewhere in your code and will also need to include the "Shlwapi.lib" library when linking.)


On the use of three slashes after a file: prefix for "localhost" URLs, see this Q/A on Super User.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83