已分配一块内存,得到这块内存的首地址,和这块内存的大小.怎么创建一个IStream类型呀?????
即: char * buf = new char[len];
再如何将这块内存变为IStream呢?有这样的问题主要是因为在使用GDI+时.创建Image时使用的函数Image::FromStream(IStream *, BOOL);是IStream接口的.
可我已经分配了一块内存,不想再用 GlobalAlloc(); 加 CreateStreamOnHGlobal(); 多分配内存了.

解决方案 »

  1.   

    可以强制类型转换后直接使用
    CreateStreamOnHGlobal
    函数进行创建。。
    譬如:IStream*   ps; 
    CreateStreamOnHGlobal((HGLOBAL)buf,FALSE,&ps);以上,没有经过测试,不过LZ可以试一下
      

  2.   

    以上的根据是:
    new是c++的标准函数,在windows的vc++编译器中,new在申请内存最终调用的是GlabalAllock
    所以,有上面的猜测LZ可以一试
    待高手确认!!
      

  3.   

    这样好像不行吧,我一开始也是想这么做的,结果运行时会出错.
    查了一下网上的资料.
    HGLOBAL是内存句柄,可能是指针的指针,并不是内存的首地址.强制转换可能没有意义.
      

  4.   


    没有什么好方法,一般来说,都是重新创建一个,然后拷贝过去。
    不过直接使用原来的内存也不是绝对不行,因为IStream是一个接口类,它的所有成员函数都是虚函数,我们可以自己继承一个IStream,然后实现它的所有成员函数,这样就可以利用已经存在的内存了。不过这绝对是一件体力活,因为比较懒,想捡现成的,不过就是没找到,后来还是直接用GlobalAlloc+CreateStreamOnHGlobal。
    如果LZ自己有兴趣实现一个,并且成功了,希望可以分享一下……
      

  5.   

    LZ可以使用 GlobalHandle 函数进行一次转换,之后再使用 CreateStreamOnHGlobal
    如下:HGLOBAL temp = GlobalHandle(buf);
    CreateStreamOnHGlobal(temp,FALSE,&ps);我查到 GlobalHandle API可以转成 HGLOBAL
      

  6.   

    呵呵~这个方法我也试过,结果运行 HGLOBAL temp = GlobalHandle(buf); 时会出错.
    我也不理解,同样是指针,为什么它的参数必须是由 LPVOID GlobalLock(HGLOBAL hMem); 得到的指针才行.
    看来内存句柄HGLOBAL在操作系统内部是有特殊管理的.
    很郁闷,为什么从内存句柄 HGLOBAL 可以得到指针, 从指针却好像不能得到内存句柄, 可能操作系统不希望用户直接使用指针.
    五楼说到的继承一个IStream可以实现直接使用原来的内存,好像可行,期待高手.
      

  7.   

    这是一个将一个文件读入IStream中的例子
    /**
    * \brief 描述: 读到IStream中.
    */
    IStream   *pStm;      
    CFileStatus   fstatus;      
    CFile   file;      
    LONG   cb;        
    if (file.Open(m_Path,CFile::modeRead)&&file.GetStatus(m_Path,fstatus)&&((cb  = fstatus.m_size) != -1))      
    {      
    HGLOBAL   hGlobal   =   GlobalAlloc(GMEM_MOVEABLE,   cb);      
    LPVOID   pvData   =   NULL;      
    if   (hGlobal   !=   NULL)      
    {      
    if   ((pvData   =   GlobalLock(hGlobal))   !=   NULL)      
    {      
    file.Read(pvData,cb);      
    GlobalUnlock(hGlobal);      
    CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);      
    }    
    }    
      

  8.   

    谢谢chogimoga 但我并不需要这个.
    我的意思是不使用 CreateStreamOnHGlobal() 如何创建一个IStream
    因为在我的应用中,已经用 new 分配了一块内存了, 想就用这块内存创建 IStream , 不想 GlobalAlloc() 分配新的内存.
      

  9.   

    本来不想写的,想想自己以后可能也会用到,就写出来,顺便蹭LZ分吧。
    注意,我只跟踪调试过Image::FromStream,把它会调用到的几个虚函数实现了一下,这对于Image::FromStream应该已经够用了,但是如果LZ要实现Image::Save,那么LZ你自己把Write等几个其他相关的虚函数也实现好了,我这里只是抛砖引玉一下。
    另外,Seek和Read我没有做多线程互斥,而实际上应该是要互斥的,反正Image::FromStream用不到,我也偷懒了。#include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <gdiplus.h>#pragma comment(lib, "gdiplus.lib")class IStreamEx : public IStream
    {
    protected:
    IStreamEx(LPVOID lpData, ULARGE_INTEGER uSize, BOOL bDeleteOnRelease)
    : m_uCount(1)
    , m_lpData(lpData)
    , m_uSize(uSize)
    , m_bDeleteOnRelease(bDeleteOnRelease)
    {
    m_uCurrent.QuadPart = 0;
    }
    ~IStreamEx()
    {
    if ((m_bDeleteOnRelease) && (m_lpData))
    free(m_lpData);
    };
    IStreamEx(const IStreamEx&) {};
    IStreamEx& operator=(const IStreamEx&)
    {
    return (*this);
    }
    public:
    static IStreamEx* CreateIStream(LPVOID lpData, DWORD dwSize, BOOL bDeleteOnRelease = FALSE)
    {
    ULARGE_INTEGER uSize = {dwSize, 0};
    return new IStreamEx(lpData, uSize, bDeleteOnRelease);
    }
    public:
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
    {
    return E_NOINTERFACE;
    }
    virtual ULONG STDMETHODCALLTYPE AddRef()
    {
    return InterlockedIncrement((LONG*)&m_uCount);
    }
    virtual ULONG STDMETHODCALLTYPE Release()
    {
    ULONG ret = InterlockedDecrement((LONG*)&m_uCount);
    if (ret == 0)
    delete this;
    return ret;
    }
    virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead)
    {
    ULONG cbr = (ULONG)(m_uSize.QuadPart - m_uCurrent.QuadPart);
    if (cbr > cb) cbr = cb;
    memcpy(pv, ((UCHAR*)m_lpData) + m_uCurrent.LowPart, cbr);
    m_uCurrent.QuadPart += cbr;
    if (pcbRead)
    *pcbRead = cbr;
    return S_OK;
    }
        virtual HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten)
    {
    return E_NOTIMPL;
    }
        virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
    {
    HRESULT ret = S_OK;
    LONGLONG lOffset = 0;
    switch (dwOrigin)
    {
    case STREAM_SEEK_SET:
    lOffset = dlibMove.QuadPart;
    break;
    case STREAM_SEEK_CUR:
    lOffset = dlibMove.QuadPart + m_uCurrent.QuadPart;
    break;
    case STREAM_SEEK_END:
    lOffset = dlibMove.QuadPart + m_uSize.QuadPart;
    break;
    default:
    ret = STG_E_INVALIDFUNCTION;
    break;
    }
    if (ret == S_OK)
    {
    if (lOffset < 0LL)
    lOffset = 0LL;
    if ((ULONGLONG)lOffset > m_uSize.QuadPart)
    lOffset = m_uSize.QuadPart;
    m_uCurrent.QuadPart = lOffset;
    if (plibNewPosition)
    plibNewPosition->QuadPart = lOffset;
    }
    return ret;
    }
        virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize)
    {
    return E_NOTIMPL;
    }
        virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
    {
    return E_NOTIMPL;
    }
        virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags)
    {
    return E_NOTIMPL;
    }
        virtual HRESULT STDMETHODCALLTYPE Revert(void)
    {
    return E_NOTIMPL;
    }
        virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
    {
    return E_NOTIMPL;
    }
        virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
    {
    return E_NOTIMPL;
    }
        virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag)
    {
    HRESULT ret = S_OK;
    if ((grfStatFlag != STATFLAG_NONAME) && (grfStatFlag != STATFLAG_DEFAULT))
    {
    ret = STG_E_INVALIDFLAG;
    }
    else if (pstatstg == NULL)
    {
    ret = STG_E_INVALIDPOINTER;
    }
    else
    {
    memset(pstatstg, 0, sizeof(STATSTG));
    pstatstg->type = STGTY_STREAM;
    pstatstg->cbSize = m_uSize;
    }
    return ret;
    }
        virtual HRESULT STDMETHODCALLTYPE Clone(IStream **ppstm)
    {
    return E_NOTIMPL;
    }
    private:
    ULONG m_uCount;
    LPVOID m_lpData;
    ULARGE_INTEGER m_uSize;
    ULARGE_INTEGER m_uCurrent;
    BOOL m_bDeleteOnRelease;
    };int main(int, char**)
    {
    void* lpBuf = NULL;
    DWORD szBuf = 0;
    FILE* fp = fopen("bk.png", "rb");
    if (fp)
    {
    fseek(fp, 0, SEEK_END);
    szBuf = (DWORD)ftell(fp);
    fseek(fp, 0, SEEK_SET);
    lpBuf = malloc(szBuf);
    if (lpBuf)
    fread(lpBuf, szBuf, 1, fp);
    fclose(fp);
    }
    if (lpBuf)
    {
    IStreamEx* pStm = IStreamEx::CreateIStream(lpBuf, szBuf);
    if (pStm)
    {
    DWORD dwToken = 0;
    Gdiplus::GdiplusStartupInput input;
    Gdiplus::GdiplusStartupOutput output;
    Gdiplus::GdiplusStartup(&dwToken, &input, &output);
    if (dwToken != 0)
    {
    Gdiplus::Bitmap* bmp = Gdiplus::Bitmap::FromStream(pStm);
    if (bmp)
    {
    if (bmp->GetLastStatus() == Gdiplus::Ok)
    {
    printf("Succeeded!\r\n");
    GUID jpg = {0x557CF401, 0x1A04, 0x11D3, 0x9A, 0x73, 0x00, 0x00, 0xF8, 0x1E, 0xF3, 0x2E};
    bmp->Save(L"bk.jpg", &jpg);
    }
    delete bmp;
    }
    Gdiplus::GdiplusShutdown(dwToken);
    }
    pStm->Release();
    }
    free(lpBuf);
    }
    system("PAUSE");
    return 0;
    }
    最后多嘴一下,在Image*存在的情况下,不要把ISteam*和相关内存释放掉,否则会出错,这个苦头以前吃过……
      

  10.   

    又看了一下,还有几个地方要修改一下,IStreamEx的成员变量最好也用protected,另外最后多嘴的部分,ISteam可以Release掉,因为它自己有引用计数,没有关系,但是相关内存一定不能释放,所以最好的方法还是IStream自己来管理内存。
      

  11.   

    w_anthony 厉害, 写的不错, 有你做的工作我就轻松多了, 呵呵, 分数是属于你的.
    贴子暂不结, 给大家再讨论讨论, 沉了就给分.