//+---------------------------------------------------------------------
//
//  File:       stgutils.hxx
//
//  Contents:   IStorage and IStream Helper functions
//
//----------------------------------------------------------------------

#include "headers.hxx"
#pragma hdrstop

//+---------------------------------------------------------------
//
//  Function:   GetMonikerDisplayName
//
//  Synopsis:   Retrieves the display name of a moniker
//
//  Arguments:  [pmk] -- the moniker for which the display name is requested
//              [ppstr] -- the place where the display name is returned
//
//  Returns:    Success iff the display name could be retrieved
//
//  Notes:      The display name string is allocated using the task allocator
//              and should be freed by the same.
//
//----------------------------------------------------------------

HRESULT
GetMonikerDisplayName(LPMONIKER pmk, LPOLESTR FAR* ppstr)
{
    HRESULT r;
    LPBC pbc;
    if (OK(r = CreateBindCtx(0, &pbc)))
    {
        r = pmk->GetDisplayName(pbc, NULL, ppstr);
        pbc->Release();
    }
    return r;
}

//+---------------------------------------------------------------
//
//  Function:   CreateStorageOnHGlobal
//
//  Synopsis:   Creates an IStorage on a global memory handle
//
//  Arguments:  [hgbl] -- memory handle to create storage on
//              [ppStg] -- where the storage is returned
//
//  Returns:    Success iff the storage could be successfully created
//              on the memory handle.
//
//  Notes:      This helper function combines CreateILockBytesOnHGlobal
//              and StgCreateDocfileOnILockBytes.  hgbl may be NULL in
//              which case a global memory handle will be automatically
//              allocated.
//
//----------------------------------------------------------------

HRESULT
CreateStorageOnHGlobal(HGLOBAL hgbl, LPSTORAGE FAR* ppStg)
{
    HRESULT r;
    LPLOCKBYTES pLockBytes;
    if (OK(r = CreateILockBytesOnHGlobal(hgbl, TRUE, &pLockBytes)))
    {
        //REVIEW:  should be use STGM_DELETEONRELEASE when hgbl == NULL?
        r = StgCreateDocfileOnILockBytes(pLockBytes,
                STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, ppStg);
        pLockBytes->Release();
    }
    return r;
}

//+---------------------------------------------------------------
//
//  Function:   ConvertToMemoryStream
//
//  Synopsis:   Takes a stream and produces an equivalent stream
//              stored in memory for faster individual reads
//
//  Arguments:  [pStrmFrom] -- the stream to convert
//
//  Returns:    An equivalent stream
//
//  Notes:      Any failure in creating the memory stream will result in
//              the original stream, pStrmFrom, being returned.
//              Hence the caller should assume the stream passed in has
//              been released and should release the stream returned
//              after it has finished using it.
//
//----------------------------------------------------------------

LPSTREAM
ConvertToMemoryStream(LPSTREAM pStrmFrom)
{
    //REVIEW:  perhaps we should use the IStream::CopyTo function
    // instead of doing the read manually!
    HRESULT r;
    LPSTREAM pStrm = NULL;
    STATSTG statstg;

    if (OK(r = pStrmFrom->Stat(&statstg, STATFLAG_NONAME)))
    {
        if (statstg.cbSize.HighPart != 0)
        {
            DOUT(TEXT("o2base/stdils/ConvertToMemoryStream E_FAIL\r\n"));
            r = E_FAIL;
        }
        else
        {
            HGLOBAL hgbl = GlobalAlloc(GMEM_SHARE, statstg.cbSize.LowPart);
            if (hgbl == NULL)
            {
               DOUT(TEXT("o2base/stgutils/ConvertToMemoryStream failed\r\n"));
               r = E_OUTOFMEMORY;
            }
            else
            {
                LPVOID pv = GlobalLock(hgbl);
                if (pv == NULL)
                {
                    DOUT(TEXT("o2base/stdils/ConvertToMemoryStream E_FAIL(2)\r\n"));
                    r = E_FAIL;
                }
                else
                {
                    r = pStrmFrom->Read(pv, statstg.cbSize.LowPart, NULL);
                    GlobalUnlock(hgbl);
                    if (OK(r))
                    {
                        if (OK(r = CreateStreamOnHGlobal(hgbl, TRUE, &pStrm)))
                        {
                            pStrm->SetSize(statstg.cbSize);
                            pStrmFrom->Release();
                        }
                        else
                        {
                            DOUT(TEXT("o2base/stdils/ConvertToMemoryStream CreateStreamOnHGlobal Failed!\r\n"));
                        }
                    }
                }
                if (!OK(r))
                {
                    GlobalFree(hgbl);
                }
            }
        }
    }

    if (!OK(r))
    {
        pStrm = pStrmFrom;
    }

    return pStrm;
}