Microsoft KB Archive/172551

From BetaArchive Wiki
< Microsoft KB Archive
Revision as of 10:06, 21 July 2020 by X010 (talk | contribs) (Text replacement - """ to """)
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