OLE IStream 的 std::ostream 接口

发布于 2024-09-02 15:54:35 字数 2321 浏览 10 评论 0原文

我有一个使用 IStreams。我想在 std::ostream 中使用 IStream 连接。像这样的事情:

IStream* stream = /*create valid IStream instance...*/; 
IStreamBuf< WIN32_FIND_DATA > sb( stream );
std::ostream os( &sb );

WIN32_FIND_DATA d = { 0 };
// send the structure along the IStream
os << d;

为了实现这一点,我实现了以下代码:

template< class _CharT, class _Traits >
inline std::basic_ostream< _CharT, _Traits >& 
operator<<( std::basic_ostream< _CharT, _Traits >& os, const WIN32_FIND_DATA& i ) 
{
    const _CharT* c = reinterpret_cast< const _CharT* >( &i );
    const _CharT* const end = c + sizeof( WIN32_FIND_DATA ) / sizeof( _CharT );
    for( c; c < end; ++c ) os << *c;
    return os;
}

template< typename T >
class IStreamBuf : public std::streambuf
{
public:
    IStreamBuf( IStream* stream ) : stream_( stream )
    {
        setp( reinterpret_cast< char* >( &buffer_ ), 
              reinterpret_cast< char* >( &buffer_ ) + sizeof( buffer_ ) );
    };

    virtual ~IStreamBuf()
    {
        sync();
    };

protected:
    traits_type::int_type FlushBuffer()
    {
        int bytes = std::min< int >( pptr() - pbase(), sizeof( buffer_ ) );

        DWORD written = 0;
        HRESULT hr = stream_->Write( &buffer_, bytes, &written );
        if( FAILED( hr ) )
        {
            return traits_type::eof();
        }

        pbump( -bytes );
        return bytes;
    };

    virtual int sync()
    {
        if( FlushBuffer() == traits_type::eof() )
            return -1;
        return 0;
    };

    traits_type::int_type overflow( traits_type::int_type ch )
    {
        if( FlushBuffer() == traits_type::eof() )
            return traits_type::eof();

        if( ch != traits_type::eof() )
        {
            *pptr() = ch;
            pbump( 1 );
        }

        return ch;
    };

private:
    /// data queued up to be sent
    T buffer_;

    /// output stream
    IStream* stream_;
}; // class IStreamBuf

是的,代码可以编译并且似乎可以工作,但我之前没有享受过实现 std::streambuf 的乐趣。所以,我只是想知道它是否正确和完整。

谢谢, 保罗·H

I have a Visual Studio 2008 C++ application using IStreams. I would like to use the IStream connection in a std::ostream. Something like this:

IStream* stream = /*create valid IStream instance...*/; 
IStreamBuf< WIN32_FIND_DATA > sb( stream );
std::ostream os( &sb );

WIN32_FIND_DATA d = { 0 };
// send the structure along the IStream
os << d;

To accomplish this, I've implemented the following code:

template< class _CharT, class _Traits >
inline std::basic_ostream< _CharT, _Traits >& 
operator<<( std::basic_ostream< _CharT, _Traits >& os, const WIN32_FIND_DATA& i ) 
{
    const _CharT* c = reinterpret_cast< const _CharT* >( &i );
    const _CharT* const end = c + sizeof( WIN32_FIND_DATA ) / sizeof( _CharT );
    for( c; c < end; ++c ) os << *c;
    return os;
}

template< typename T >
class IStreamBuf : public std::streambuf
{
public:
    IStreamBuf( IStream* stream ) : stream_( stream )
    {
        setp( reinterpret_cast< char* >( &buffer_ ), 
              reinterpret_cast< char* >( &buffer_ ) + sizeof( buffer_ ) );
    };

    virtual ~IStreamBuf()
    {
        sync();
    };

protected:
    traits_type::int_type FlushBuffer()
    {
        int bytes = std::min< int >( pptr() - pbase(), sizeof( buffer_ ) );

        DWORD written = 0;
        HRESULT hr = stream_->Write( &buffer_, bytes, &written );
        if( FAILED( hr ) )
        {
            return traits_type::eof();
        }

        pbump( -bytes );
        return bytes;
    };

    virtual int sync()
    {
        if( FlushBuffer() == traits_type::eof() )
            return -1;
        return 0;
    };

    traits_type::int_type overflow( traits_type::int_type ch )
    {
        if( FlushBuffer() == traits_type::eof() )
            return traits_type::eof();

        if( ch != traits_type::eof() )
        {
            *pptr() = ch;
            pbump( 1 );
        }

        return ch;
    };

private:
    /// data queued up to be sent
    T buffer_;

    /// output stream
    IStream* stream_;
}; // class IStreamBuf

Yes, the code compiles and seems to work, but I've not had the pleasure of implementing a std::streambuf before. So, I'd just like to know if it's correct and complete.

Thanks,
PaulH

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浮云落日 2024-09-09 15:54:35

我不久前编写的一个实现: https://github.com/senderista/UnbufferedOLEStreamBuf

这是 大多数情况下,您只需要在 STL 和 Windows/COM 类型之间进行机械转换。不过,这种翻译很乏味且容易出错,因此您可能最好使用我链接的实现。它只有 150 行,它是在生产应用程序中使用的,并且几乎没有隐藏 bug 的地方。

由于显然答案中的链接会导致删除,因此这里是完整的代码:

//Copyright (c) 2010 Tobin Baker
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.


#include <ios>
#include <streambuf>
#include <windows.h>

// Read-write unbuffered streambuf implementation which uses no
// internal buffers (conventional wisdom says this can't be done
// except for write-only streams, but I adapted Matt Austern's example
// from http://www.drdobbs.com/184401305).

class UnbufferedOLEStreamBuf : public std::streambuf {
public:
    UnbufferedOLEStreamBuf(IStream *stream, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
    ~UnbufferedOLEStreamBuf();

protected:
    virtual int overflow(int ch = traits_type::eof());
    virtual int underflow();
    virtual int uflow();
    virtual int pbackfail(int ch = traits_type::eof());
    virtual int sync();
    virtual std::streampos seekpos(std::streampos sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
    virtual std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
    virtual std::streamsize xsgetn(char *s, std::streamsize n);
    virtual std::streamsize xsputn(const char *s, std::streamsize n);
    virtual std::streamsize showmanyc();

private:
    IStream *stream_;
    bool readOnly_;
    bool backup();
};

UnbufferedOLEStreamBuf::UnbufferedOLEStreamBuf(IStream *stream, std::ios_base::openmode which)
: std::streambuf(), stream_(stream), readOnly_(!(which & std::ios_base::out)) {}

UnbufferedOLEStreamBuf::~UnbufferedOLEStreamBuf() { if (!readOnly_) UnbufferedOLEStreamBuf::sync(); }

bool UnbufferedOLEStreamBuf::backup() {
    LARGE_INTEGER liMove;
    liMove.QuadPart = -1LL;
    return SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_CUR, NULL));
}

int UnbufferedOLEStreamBuf::overflow(int ch) {
    if (ch != traits_type::eof()) {
        if (SUCCEEDED(stream_->Write(&ch, 1, NULL))) {
            return ch;
        }
    }
    return traits_type::eof();
}

int UnbufferedOLEStreamBuf::underflow() {
    char ch = UnbufferedOLEStreamBuf::uflow();
    if (ch != traits_type::eof()) {
        ch = backup() ? ch : traits_type::eof();
    }
    return ch;
}

int UnbufferedOLEStreamBuf::uflow() {
    char ch;
    ULONG cbRead;
    // S_FALSE indicates we've reached end of stream
    return (S_OK == stream_->Read(&ch, 1, &cbRead))
        ? ch : traits_type::eof();
}

int UnbufferedOLEStreamBuf::pbackfail(int ch) {
    if (ch != traits_type::eof()) {
        ch = backup() ? ch : traits_type::eof();
    }
    return ch;
}

int UnbufferedOLEStreamBuf::sync() {
    return SUCCEEDED(stream_->Commit(STGC_DEFAULT)) ? 0 : -1;
}

std::ios::streampos UnbufferedOLEStreamBuf::seekpos(std::ios::streampos sp, std::ios_base::openmode which) {
    LARGE_INTEGER liMove;
    liMove.QuadPart = sp;
    return SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_SET, NULL)) ? sp : -1;
}

std::streampos UnbufferedOLEStreamBuf::seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) {
    STREAM_SEEK sk;
    switch (way) {
        case std::ios_base::beg: sk = STREAM_SEEK_SET; break;
        case std::ios_base::cur: sk = STREAM_SEEK_CUR; break;
        case std::ios_base::end: sk = STREAM_SEEK_END; break;
        default: return -1;
    }
    LARGE_INTEGER liMove;
    liMove.QuadPart = static_cast<LONGLONG>(off);
    ULARGE_INTEGER uliNewPos;
    return SUCCEEDED(stream_->Seek(liMove, sk, &uliNewPos))
        ? static_cast<std::streampos>(uliNewPos.QuadPart) : -1;
}

std::streamsize UnbufferedOLEStreamBuf::xsgetn(char *s, std::streamsize n) {
    ULONG cbRead;
    return SUCCEEDED(stream_->Read(s, static_cast<ULONG>(n), &cbRead))
        ? static_cast<std::streamsize>(cbRead) : 0;
}

std::streamsize UnbufferedOLEStreamBuf::xsputn(const char *s, std::streamsize n) {
    ULONG cbWritten;
    return SUCCEEDED(stream_->Write(s, static_cast<ULONG>(n), &cbWritten))
        ? static_cast<std::streamsize>(cbWritten) : 0;
}

std::streamsize UnbufferedOLEStreamBuf::showmanyc() {
    STATSTG stat;
    if (SUCCEEDED(stream_->Stat(&stat, STATFLAG_NONAME))) {
        std::streampos lastPos = static_cast<std::streampos>(stat.cbSize.QuadPart - 1);
        LARGE_INTEGER liMove;
        liMove.QuadPart = 0LL;
        ULARGE_INTEGER uliNewPos;
        if (SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_CUR, &uliNewPos))) {
            return std::max<std::streamsize>(lastPos - static_cast<std::streampos>(uliNewPos.QuadPart), 0);
        }
    }
    return 0;
}

std::streambuf* StdStreamBufFromOLEStream(IStream *pStream, std::ios_base::openmode which)
{
    return new (std::nothrow) UnbufferedOLEStreamBuf(pStream, which);
}

希望这会有所帮助。

Here's an implementation I wrote a while ago: https://github.com/senderista/UnbufferedOLEStreamBuf

For the most part you just need to mechanically translate between STL and Windows/COM types. This translation is tedious and error-prone, though, so you would probably be best off using the implementation I linked. It's only 150 lines, it was used in a production application, and there are few places for bugs to hide.

Since apparently links in answers are cause for deletion, here's the code in its entirety:

//Copyright (c) 2010 Tobin Baker
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.


#include <ios>
#include <streambuf>
#include <windows.h>

// Read-write unbuffered streambuf implementation which uses no
// internal buffers (conventional wisdom says this can't be done
// except for write-only streams, but I adapted Matt Austern's example
// from http://www.drdobbs.com/184401305).

class UnbufferedOLEStreamBuf : public std::streambuf {
public:
    UnbufferedOLEStreamBuf(IStream *stream, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
    ~UnbufferedOLEStreamBuf();

protected:
    virtual int overflow(int ch = traits_type::eof());
    virtual int underflow();
    virtual int uflow();
    virtual int pbackfail(int ch = traits_type::eof());
    virtual int sync();
    virtual std::streampos seekpos(std::streampos sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
    virtual std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
    virtual std::streamsize xsgetn(char *s, std::streamsize n);
    virtual std::streamsize xsputn(const char *s, std::streamsize n);
    virtual std::streamsize showmanyc();

private:
    IStream *stream_;
    bool readOnly_;
    bool backup();
};

UnbufferedOLEStreamBuf::UnbufferedOLEStreamBuf(IStream *stream, std::ios_base::openmode which)
: std::streambuf(), stream_(stream), readOnly_(!(which & std::ios_base::out)) {}

UnbufferedOLEStreamBuf::~UnbufferedOLEStreamBuf() { if (!readOnly_) UnbufferedOLEStreamBuf::sync(); }

bool UnbufferedOLEStreamBuf::backup() {
    LARGE_INTEGER liMove;
    liMove.QuadPart = -1LL;
    return SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_CUR, NULL));
}

int UnbufferedOLEStreamBuf::overflow(int ch) {
    if (ch != traits_type::eof()) {
        if (SUCCEEDED(stream_->Write(&ch, 1, NULL))) {
            return ch;
        }
    }
    return traits_type::eof();
}

int UnbufferedOLEStreamBuf::underflow() {
    char ch = UnbufferedOLEStreamBuf::uflow();
    if (ch != traits_type::eof()) {
        ch = backup() ? ch : traits_type::eof();
    }
    return ch;
}

int UnbufferedOLEStreamBuf::uflow() {
    char ch;
    ULONG cbRead;
    // S_FALSE indicates we've reached end of stream
    return (S_OK == stream_->Read(&ch, 1, &cbRead))
        ? ch : traits_type::eof();
}

int UnbufferedOLEStreamBuf::pbackfail(int ch) {
    if (ch != traits_type::eof()) {
        ch = backup() ? ch : traits_type::eof();
    }
    return ch;
}

int UnbufferedOLEStreamBuf::sync() {
    return SUCCEEDED(stream_->Commit(STGC_DEFAULT)) ? 0 : -1;
}

std::ios::streampos UnbufferedOLEStreamBuf::seekpos(std::ios::streampos sp, std::ios_base::openmode which) {
    LARGE_INTEGER liMove;
    liMove.QuadPart = sp;
    return SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_SET, NULL)) ? sp : -1;
}

std::streampos UnbufferedOLEStreamBuf::seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) {
    STREAM_SEEK sk;
    switch (way) {
        case std::ios_base::beg: sk = STREAM_SEEK_SET; break;
        case std::ios_base::cur: sk = STREAM_SEEK_CUR; break;
        case std::ios_base::end: sk = STREAM_SEEK_END; break;
        default: return -1;
    }
    LARGE_INTEGER liMove;
    liMove.QuadPart = static_cast<LONGLONG>(off);
    ULARGE_INTEGER uliNewPos;
    return SUCCEEDED(stream_->Seek(liMove, sk, &uliNewPos))
        ? static_cast<std::streampos>(uliNewPos.QuadPart) : -1;
}

std::streamsize UnbufferedOLEStreamBuf::xsgetn(char *s, std::streamsize n) {
    ULONG cbRead;
    return SUCCEEDED(stream_->Read(s, static_cast<ULONG>(n), &cbRead))
        ? static_cast<std::streamsize>(cbRead) : 0;
}

std::streamsize UnbufferedOLEStreamBuf::xsputn(const char *s, std::streamsize n) {
    ULONG cbWritten;
    return SUCCEEDED(stream_->Write(s, static_cast<ULONG>(n), &cbWritten))
        ? static_cast<std::streamsize>(cbWritten) : 0;
}

std::streamsize UnbufferedOLEStreamBuf::showmanyc() {
    STATSTG stat;
    if (SUCCEEDED(stream_->Stat(&stat, STATFLAG_NONAME))) {
        std::streampos lastPos = static_cast<std::streampos>(stat.cbSize.QuadPart - 1);
        LARGE_INTEGER liMove;
        liMove.QuadPart = 0LL;
        ULARGE_INTEGER uliNewPos;
        if (SUCCEEDED(stream_->Seek(liMove, STREAM_SEEK_CUR, &uliNewPos))) {
            return std::max<std::streamsize>(lastPos - static_cast<std::streampos>(uliNewPos.QuadPart), 0);
        }
    }
    return 0;
}

std::streambuf* StdStreamBufFromOLEStream(IStream *pStream, std::ios_base::openmode which)
{
    return new (std::nothrow) UnbufferedOLEStreamBuf(pStream, which);
}

Hope this helps.

故事未完 2024-09-09 15:54:35

我的建议是使用 Boost.IOStreams Device 包装IStream。它负责处理所有 C++ IO 流内容,因此您无需这样做。

My suggestion would be to use Boost.IOStreams Device to wrap the IStream. It takes care of all of the C++ IO streams stuff so that you do not have to.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文