Microsoft KB Archive/172551

From BetaArchive Wiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Knowledge Base


PRB: CInternetSession::OpenURL() Fails with File Protocol

Article ID: 172551

Article Last Modified on 3/7/2005



APPLIES TO

  • Microsoft Foundation Class Library 4.2, when used with:
    • Microsoft Visual C++ 5.0 Enterprise Edition
    • Microsoft Visual C++ 5.0 Professional Edition
    • Microsoft Visual C++ 6.0 Enterprise Edition
    • Microsoft Visual C++ 6.0 Professional Edition
    • Microsoft Visual C++ 6.0 Standard Edition



This article was previously published under Q172551

SYMPTOMS

CInternetSession::OpenURL() fails if you use a URL that specifies a file that contains spaces or other unsafe characters. For example, the following will fail:

   CMyInternetSession s("");
   CStdioFile* p = s.OpenURL("file://c:/temp/Text Document.txt");
                

As a result, a File Exception is thrown and the following message appears:

c:\temp\Text%20Document.txt was not found.

CAUSE

The specifications for a URL designate certain characters that must be escaped when they are present in a URL. The space character is one of the characters that must be escaped.

The function CInternetSession::OpenURL() calls a function that converts unsafe characters in the URL to their escape sequences before processing the URL further. If the URL is using the file protocol it creates a CStdioFile and returns a pointer to this object. However, CStdioFile does not understand the escaped path and, as a result, an exception is thrown.

RESOLUTION

When you use the file protocol, you must not convert unsafe characters to their escape sequences. The following code demonstrates how to do this by writing a CInternetSession derived class to override OpenURL().

   // class definition
   class CMyInternetSession : CInternetSession
   {
   public:
      CMyInternetSession::CMyInternetSession(LPCTSTR pstrAgent = NULL,
         DWORD dwContext = 1, DWORD dwAccessType =
         PRE_CONFIG_INTERNET_ACCESS, LPCTSTR pstrProxyName = NULL,
         LPCTSTR pstrProxyBypass = NULL, DWORD dwFlags = 0);

      CStdioFile* CMyInternetSession::OpenURL(LPCTSTR pstrURL,
         DWORD dwContext = 1, DWORD dwFlags =
         INTERNET_FLAG_TRANSFER_ASCII, LPCTSTR pstrHeaders = NULL,
         DWORD dwHeadersLength = 0);
   };

   // CMyInternetSession constructor
   CMyInternetSession::CMyInternetSession(LPCTSTR pstrAgent,
      DWORD dwContext, DWORD dwAccessType, LPCTSTR pstrProxyName,
      LPCTSTR pstrProxyBypass, DWORD dwFlags)
   {
      CInternetSession(pstrAgent, dwContext, dwAccessType, pstrProxyName,
         pstrProxyBypass, dwFlags);
   }

   CStdioFile* CMyInternetSession::OpenURL(LPCTSTR pstrURL,
      DWORD dwContext, DWORD dwFlags, LPCTSTR pstrHeaders,
      DWORD dwHeadersLength)
   {
      ASSERT(pstrURL != NULL);
      ASSERT(dwHeadersLength == 0 || pstrHeaders != NULL);

      // must have TRANSFER_BINARY or TRANSFER_ASCII but not both
      #define _AFX_TRANSFER_MASK (INTERNET_FLAG_TRANSFER_BINARY \ 
         | INTERNET_FLAG_TRANSFER_ASCII)

      ASSERT((dwFlags & _AFX_TRANSFER_MASK) != 0);
      ASSERT((dwFlags & _AFX_TRANSFER_MASK) != _AFX_TRANSFER_MASK);

      DWORD dwServiceType;
      CString strServer;
      CString strObject;
      INTERNET_PORT nPort;

      BOOL bParsed = AfxParseURL(pstrURL, dwServiceType,
         strServer, strObject, nPort);

      // if it turns out to be a file...
      if (bParsed && dwServiceType == AFX_INET_SERVICE_FILE)
      {
         CString userName;
         CString password;

         // Get the normalized file name with out converting
         // unsafe characters to escape sequence.

         AfxParseURLEx(pstrURL, dwServiceType, strServer,
            strObject, nPort, userName, password, ICU_NO_ENCODE);

         int nMode = CFile::modeRead | CFile::shareCompat;
         if (dwFlags & INTERNET_FLAG_TRANSFER_BINARY)
            nMode |= CFile::typeBinary;
         else
            nMode |= CFile::typeText;

         return new CStdioFile(strObject, nMode);
      }

      return CInternetSession::OpenURL(pstrURL,   dwContext, dwFlags,
         pstrHeaders, dwHeadersLength);
   }
                

REFERENCES

The specification for URL's are published by The World Wide Web Consortium (W3C). The specifications define the escape sequences and unsafe characters. Its URL is:

NOTE: Web links may change without notice.


Additional query words: 4.20b space file OpenURL filename

Keywords: kbprb KB172551