none
[UWP][C++] Using IRandomAccessStream^ will throws ObjectDisposedException RRS feed

  • 问题

  • I want to wrap the file stream operation interface to provide other library calls, but throw an  ObjectDisposedException when calling them:

    The following is the sample code snippet:

    class ImageFileStream {
    public:
    	ImageFileStream(IRandomAccessStream ^);
    	~ImageFileStream();
    	void Skip( long );
    	void Rewind( void );
    	size_t Read( unsigned char*, size_t );
    private:
    	IRandomAccessStream ^m_stream;
    };
    
    ImageFileStream::ImageFileStream( IRandomAccessStream ^stream )
    {
    	m_stream = stream;
    }
    
    ImageFileStream::~ImageFileStream()
    {
    	
    }
    
    size_t ImageFileStream::Read( unsigned char *buffer, size_t size )
    {
    	DataReader ^reader = ref new DataReader( m_stream );
    	return create_task( reader->LoadAsync( static_cast<UINT32>(size) ) ).then( [reader, buffer]( size_t size ) {
    		auto data = ref new Array<unsigned char>( size );
    		reader->ReadBytes( data );
    		memcpy( (void*)buffer, (void*)data->Data, size );
    		return size;
    	} ).get();
    }
    
    void ImageFileStream::Skip( long offset )
    {
    	m_stream->Seek( m_stream->Position + offset );
    }
    
    void ImageFileStream::Rewind( void )
    {
    	m_stream->Seek( 0 );
    }
    
    static void FileOnRewind( void *data )
    {
    	ImageFileStream *stream = (ImageFileStream*)data;
    	stream->Rewind();
    }
    
    static void FileOnSkip( void *data, long count )
    {
    	ImageFileStream *stream = (ImageFileStream*)data;
    	stream->Skip( count );
    }
    
    static size_t FileOnRead( void *data, void *buffer, size_t size )
    {
    	ImageFileStream *stream = (ImageFileStream*)data;
    	return stream->Read( (unsigned char*)buffer, size );
    }
    
    static void LCUI_SetImageReader( LCUI_ImageReader reader, ImageFileStream *stream )
    {
    	reader->stream_data = (void*)stream;
    	reader->fn_rewind = FileOnRewind;
    	reader->fn_read = FileOnRead;
    	reader->fn_skip = FileOnSkip;
    }

    I call it in the code like this:

    	StorageFile^ file;
    
    	...
    
    	auto t = create_task( file->OpenAsync( FileAccessMode::Read ) );
    	return t.then( [conn, params, chunk, file]( task<IRandomAccessStream^> t ) {
    		LCUI_ImageReaderRec reader = { 0 };
    		IRandomAccessStream ^stream = nullptr;
    		try {
    			stream = t.get();
    		} catch( COMException^ ex ) {
    			return -ENODATA;
    		}
    		auto data = ImageFileStream( stream );
    		LCUI_SetImageReader( &reader, &data );
    		FileService_ReadImage( conn, params, chunk, &reader );
    		return 0;
    	} ).get();


    How to solve this problem?

    I found this document: https://msdn.microsoft.com/en-us/library/xey702bw.aspx , It seems that using pin_ptr can extend the life cycle of stream variable, but pin_ptr cannot use in my code, because the compiler will give some error messages.


    2017年2月26日 12:58

答案

  • Hello lc-soft,

    You might need to call DataReader::DetachStream() so that the stream won't be closed.

    size_t ImageFileStream::Read( unsigned char *buffer, size_t size )
    {
            DataReader ^reader = ref new DataReader( m_stream );
            return create_task( reader->LoadAsync( static_cast<UINT32>(size) ) ).then( [reader, buffer]( size_t size ) {
            auto data = ref new Array<unsigned char>( size );
            reader->ReadBytes( data );
            reader->DetachStream();
            memcpy( (void*)buffer, (void*)data->Data, size );
            return size;
        } ).get();
    }
    • 已标记为答案 lc-soft 2017年2月27日 14:44
    2017年2月27日 1:27

全部回复

  • Hello lc-soft,

    You might need to call DataReader::DetachStream() so that the stream won't be closed.

    size_t ImageFileStream::Read( unsigned char *buffer, size_t size )
    {
            DataReader ^reader = ref new DataReader( m_stream );
            return create_task( reader->LoadAsync( static_cast<UINT32>(size) ) ).then( [reader, buffer]( size_t size ) {
            auto data = ref new Array<unsigned char>( size );
            reader->ReadBytes( data );
            reader->DetachStream();
            memcpy( (void*)buffer, (void*)data->Data, size );
            return size;
        } ).get();
    }
    • 已标记为答案 lc-soft 2017年2月27日 14:44
    2017年2月27日 1:27
  • Oh, your method is awesome, good job!
    2017年2月27日 14:39