BUG: MSXML Component Fails When Loading Local Files (301935)



The information in this article applies to:

  • Microsoft Windows CE Platform SDK for Pocket PC

This article was previously published under Q301935

SYMPTOMS

When you are specifying a path to a local file in a call to IXMLDOMDocument::load(), the call returns a success value of FALSE, and the dispatch invoke method returns "0x00000001".

RESOLUTION

To work around this problem, implement an IStream interface to access local files.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

The following is a simple example of how to implement an IStream interface to support ftp, http, and local file protocols. Use the static function CMyStream::Create to create the stream.
#pragma once

#include <wininet.h>

struct CMyFileStream;
struct CMyFtpStream;
struct CMyHttpStream;

class CMyStream : public IStream
{

    LONG    m_lRefCount;

public:

    CMyStream()
    {
        m_lRefCount = 1;
    }

    ~CMyStream()
    {
        Close();
    }

    HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void ** ppi )
    {
        if (riid == IID_IUnknown)
            *ppi = static_cast<IUnknown*>(this);

        else if (riid == IID_IStream)
            *ppi = static_cast<IStream*>(this);

        else
            return E_NOINTERFACE;

        reinterpret_cast<IUnknown*>(*ppi)->AddRef();

        return S_OK;
    }

    ULONG STDMETHODCALLTYPE AddRef( void )
    {
        return InterlockedIncrement( &m_lRefCount );
    }

    ULONG STDMETHODCALLTYPE Release( void )
    {
        if ( InterlockedDecrement( &m_lRefCount ) == 0 )
        {
            delete this;
            return 0;
        }
        return (ULONG)m_lRefCount;
    }

    HRESULT STDMETHODCALLTYPE Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE SetSize( ULARGE_INTEGER libNewSize) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE CopyTo( IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE Commit( DWORD grfCommitFlags) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE Revert( void) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE LockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE UnlockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE Stat( STATSTG* pstatstg, DWORD grfStatFlag) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE Clone( IStream** ppstm) { return E_NOTIMPL; }

    virtual BOOL Open( LPCTSTR lpszName, BOOL fRead = TRUE ) = 0;
    virtual BOOL Close() = 0 { return FALSE; }

    static IStream* Create( LPCTSTR lpszName, BOOL fRead = TRUE );
};

struct CMyFtpStream : public CMyStream
{
    CMyFtpStream()
    {
        m_hConnect = 0;
        m_hSession = 0;
        m_hFile = 0;
    }

    HRESULT STDMETHODCALLTYPE Read( void* pv, DWORD cb, DWORD* pcbRead )
    {   
        if ( !m_hFile )
            return E_FAIL;

        DWORD dwActual;

        if( !InternetReadFile( m_hFile, pv, cb, pcbRead ? pcbRead : &dwActual ) )
            return FALSE;

        return S_OK;
    }
    
    HRESULT STDMETHODCALLTYPE Write( const void* pv, DWORD cb, DWORD* pcbWritten )
    {
        return E_NOTIMPL;
    }

    BOOL Open( LPCTSTR lpszName, BOOL fRead = TRUE )
    {
        if ( !fRead )
            return E_NOTIMPL;


        URL_COMPONENTS  uc;
        TCHAR           achHostName[256];
        TCHAR           achUrlPath[256];

        m_hSession = InternetOpen( TEXT(""), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0 );
        if ( !m_hSession )
            return FALSE;

        memset( &uc, 0, sizeof(uc) );
        uc.dwStructSize = sizeof(uc);
        uc.lpszHostName = achHostName;
        uc.dwHostNameLength = 256;
        uc.lpszUrlPath = achUrlPath;
        uc.dwUrlPathLength = 256;

        InternetCrackUrl( lpszName, 0, ICU_ESCAPE, &uc );

        m_hConnect = InternetConnect( m_hSession, achHostName, INTERNET_DEFAULT_FTP_PORT, 0, 0, INTERNET_SERVICE_FTP, 0, 0 );
        if ( !m_hConnect )
            return FALSE;

        FtpOpenFile( m_hConnect, achUrlPath, GENERIC_READ, FTP_TRANSFER_TYPE_BINARY|INTERNET_FLAG_NO_CACHE_WRITE, 0 );
        if ( !m_hFile )
            return FALSE;


        return TRUE;
    }

    BOOL Close()
    {
        if ( m_hConnect )
            InternetCloseHandle( m_hConnect );
        if ( m_hSession )
            InternetCloseHandle( m_hSession );

        return TRUE;
    }

private:

    HINTERNET   m_hFile;
    HINTERNET   m_hSession;
    HINTERNET   m_hConnect;
};

struct CMyHttpStream : public CMyStream
{
    CMyHttpStream()
    {
        m_hRequest = 0;
        m_hConnect = 0;
        m_hSession = 0;
    }

    HRESULT STDMETHODCALLTYPE Read( void* pv, DWORD cb, DWORD* pcbRead )
    {   
        if ( !m_hRequest )
            return E_FAIL;

        DWORD dwActual;

        if( !InternetReadFile( m_hRequest, pv, cb, pcbRead ? pcbRead : &dwActual ) )
            return FALSE;

        return S_OK;
    }
    
    HRESULT STDMETHODCALLTYPE Write( const void* pv, DWORD cb, DWORD* pcbWritten )
    {
        return E_NOTIMPL;
    }

    BOOL Open( LPCTSTR lpszName, BOOL fRead = TRUE )
    {
        if ( !fRead )
            return E_NOTIMPL;


        URL_COMPONENTS  uc;
        TCHAR           achHostName[256];
        TCHAR           achUrlPath[256];

        m_hSession = InternetOpen( TEXT(""), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0 );
        if ( !m_hSession )
            return FALSE;

        memset( &uc, 0, sizeof(uc) );
        uc.dwStructSize = sizeof(uc);
        uc.lpszHostName = achHostName;
        uc.dwHostNameLength = 256;
        uc.lpszUrlPath = achUrlPath;
        uc.dwUrlPathLength = 256;

        InternetCrackUrl( lpszName, 0, ICU_ESCAPE, &uc );

        m_hConnect = InternetConnect( m_hSession, achHostName, INTERNET_DEFAULT_HTTP_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, 0 );
        if ( !m_hConnect )
            return FALSE;

        m_hRequest = HttpOpenRequest( m_hConnect, TEXT("GET"), achUrlPath, 0, 0, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0 );
        if ( !m_hRequest )
            return FALSE;

        if ( !HttpSendRequest( m_hRequest, 0, 0, 0, 0 ) )
            return FALSE;

        return TRUE;
    }

    BOOL Close()
    {
        if ( m_hRequest )
            InternetCloseHandle( m_hRequest );
        if ( m_hConnect )
            InternetCloseHandle( m_hConnect );
        if ( m_hSession )
            InternetCloseHandle( m_hSession );

        return TRUE;
    }

private:

    HINTERNET   m_hSession;
    HINTERNET   m_hConnect;
    HINTERNET   m_hRequest;
};

struct CMyFileStream : public CMyStream
{

    CMyFileStream()
    {
        m_file = 0;
    }

    HRESULT STDMETHODCALLTYPE Read( void* pv, DWORD cb, DWORD* pcbRead )
    {   
        if ( !m_fRead || !m_file )
            return S_FALSE;

        if ( !cb )
            return S_OK;

        size_t actual = (ULONG)fread( pv, 1, cb, m_file );

        if ( pcbRead )
            *pcbRead = (DWORD)actual;

        return ( actual ? S_OK : S_FALSE ); 
    }
    
    HRESULT STDMETHODCALLTYPE Write( const void* pv, DWORD cb, DWORD* pcbWritten )
    {
        if ( m_fRead || !m_file )
            return S_FALSE;

        if ( !cb )
            return S_OK;

        size_t actual = fwrite( pv, 1, cb, m_file );

        if ( pcbWritten )
            *pcbWritten = (DWORD)actual;

        return ( actual ? S_OK : S_FALSE ); 
    }

    BOOL Open( LPCTSTR lpszName, BOOL fRead = TRUE )
    {
        LPCTSTR lpszNoProtocol = lpszName;

        m_fRead = fRead;

        if ( !_tcsnicmp( lpszName, TEXT("FILE://"), 7 ) )
            lpszNoProtocol += 7;
        else if ( !_tcsnicmp( lpszName, TEXT("FILE:"), 5 ) )
            lpszNoProtocol += 5;

        return 0 != ( m_file = _tfopen( lpszNoProtocol, fRead ? TEXT("rb") : TEXT("wb") ) );
    }

    BOOL Close()
    {
        if ( m_file )
            return ( 0 == fclose( m_file ) );
        else
            return FALSE;
    }

private:

    FILE*       m_file;
    BOOL        m_fRead;

};


IStream* CMyStream::Create( LPCTSTR lpszName, BOOL fRead )
{
    CMyStream*  pNewStream;

    if ( !_tcsnicmp( lpszName, TEXT("HTTP:"), 5 ) )
        pNewStream = new CMyHttpStream;
    else if ( !_tcsnicmp( lpszName, TEXT("FTP:"), 4 ) )
        pNewStream = new CMyFtpStream;
    else if ( !_tcsnicmp( lpszName, TEXT("FILE:"), 5 ) )
        pNewStream = new CMyFileStream;
    else
        pNewStream = new CMyFileStream;

    if ( !pNewStream )
        return 0;

    if ( pNewStream->Open( lpszName, fRead ) )
        return static_cast<IStream*>(pNewStream);

    delete pNewStream;
    return 0;
}
				
Here is an example of how the stream class might be used:
    if ( IStream* pStream = CMyStream::Create( L"file://\\wehavenobananas.xml" ) )
    {
        VARIANT_BOOL    vSuccess = VARIANT_FALSE;
        VARIANT         vSource;

        VariantInit( &vSource );
        vSource.punkVal = pStream;
        vSource.vt = VT_UNKNOWN;

        pDocument->load( vSource, &vSuccess );

        pStream->Release();

        fLoaded = ( VARIANT_TRUE == vSuccess );
    }
				

REFERENCES

For additional information, click the following article numbers to view the articles in the Microsoft Knowledge Base:

301939 How to add MSXML support to a C++ application


Modification Type:MajorLast Reviewed:9/10/2004
Keywords:kbbug kbpending KB301935