g//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1993.
//
//  File:	ofsenm.cxx
//
//  Contents:	File storage enumerator
//
//  History:	21-Jul-93	DrewB	Created
//
//----------------------------------------------------------------------------

#include "headers.cxx"
#pragma hdrstop

#include "ofsenm.hxx"

//+---------------------------------------------------------------------------
//
//  Member:     COfsFileEnum::QueryInterface, public
//
//  Synopsis:   Returns an object for the requested interface
//
//  Arguments:  [iid] - Interface ID
//              [ppvObj] - Object return
//
//  Returns:    Appropriate status code
//
//  Modifies:   [ppvObj]
//
//  History:    21-Jul-93       DrewB   Created
//
//----------------------------------------------------------------------------

STDMETHODIMP COfsFileEnum::QueryInterface(REFIID iid, void **ppvObj)
{
    SCODE sc;

    ssDebugOut((DEB_TRACE, "In  COfsFileEnum::QueryInterface:%p(riid, %p)\n",
                this, ppvObj));
    if (!IsValidIid(iid))
        ssErr(EH_Err, STG_E_INVALIDPARAMETER);
    ssChk(Validate());
    if (IsEqualIID(iid, IID_IEnumSTATSTG) || IsEqualIID(iid, IID_IUnknown))
    {
        *ppvObj = (IEnumSTATSTG *)this;
        COfsFileEnum::AddRef();
    }
    else
    {
        sc = E_NOINTERFACE;
        *ppvObj = NULL;
    }
    ssDebugOut((DEB_TRACE, "Out COfsFileEnum::QueryInterface => %p\n",
                *ppvObj));
 EH_Err:
    return ssResult(sc);
}

//+---------------------------------------------------------------------------
//
//  Member:	COfsFileEnum::COfsFileEnum, public
//
//  Synopsis:	Constructor
//
//  History:	21-Jul-93	DrewB	Created
//
//----------------------------------------------------------------------------

COfsFileEnum::COfsFileEnum(void)
{
    ssDebugOut((DEB_ITRACE, "In  COfsFileEnum::COfsFileEnum:%p()\n", this));
    _sig = 0;
    ssDebugOut((DEB_ITRACE, "Out COfsFileEnum::COfsFileEnum\n"));
    ENLIST_TRACKING(COfsFileEnum);
}

//+---------------------------------------------------------------------------
//
//  Member:	COfsFileEnum::InitFromHandle, public
//
//  Synopsis:	Initializes from the given information
//
//  Arguments:	[h] - Handle
//              [fDone] - Done status
//
//  Returns:	Appropriate status code
//
//  History:	21-Jul-93	DrewB	Created
//
//  Notes:      Takes a new reference on the handle
//
//----------------------------------------------------------------------------

SCODE COfsFileEnum::InitFromHandle(HANDLE h, BOOL fDone)
{
    SCODE sc;
    
    ssDebugOut((DEB_ITRACE, "In  COfsFileEnum::InitFromHandle:%p(%p, %d)\n",
                this, h, fDone));
    
    ssChk(DupNtHandle(h, &_h));

    _fDone = fDone;
    _sig = COFSFILEENUM_SIG;
    
    ssDebugOut((DEB_ITRACE, "Out COfsFileEnum::InitFromHandle\n"));
 EH_Err:
    return sc;
}

//+---------------------------------------------------------------------------
//
//  Member:	COfsFileEnum::~COfsFileEnum, public
//
//  Synopsis:	Destructor
//
//  History:	21-Jul-93	DrewB	Created
//
//----------------------------------------------------------------------------

COfsFileEnum::~COfsFileEnum(void)
{
    ssDebugOut((DEB_ITRACE, "In  COfsFileEnum::~COfsFileEnum:%p()\n", this));
    _sig = COFSFILEENUM_SIGDEL;
    ssDebugOut((DEB_ITRACE, "Out COfsFileEnum::~COfsFileEnum\n"));
}

//+--------------------------------------------------------------
//
//  Member:     COfsFileEnum::Next, public
//
//  Synopsis:   Gets N entries from an iterator
//
//  Arguments:  [celt] - Count of elements
//              [rgelt] - Array for element return
//              [pceltFetched] - If non-NULL, contains the number of
//                      elements fetched
//
//  Returns:    Appropriate status code
//
//  Modifies:   [rgelt]
//              [pceltFetched]
//
//  History:    21-Jul-93       DrewB   Created
//
//---------------------------------------------------------------

STDMETHODIMP COfsFileEnum::Next(ULONG celt,
                             STATSTG *rgelt,
                             ULONG *pceltFetched)
{
    SCODE sc;
    STATSTG stat;
    FILE_STANDARD_INFORMATION fi;
    NTSTATUS nts;
    IO_STATUS_BLOCK iosb;

    ssDebugOut((DEB_TRACE, "In  COfsFileEnum::Next:%p(%lu, %p, %p)\n",
                this, celt, rgelt, pceltFetched));
    
    if (pceltFetched == NULL && celt > 1)
        ssErr(EH_Err, STG_E_INVALIDPARAMETER);
    ssChk(Validate());
    
    ssAssert(_h != NULL);
    __try
    {
        if (celt == 0)
        {
            if (pceltFetched)
                *pceltFetched = 0;
            ssErr(EH_Err, S_OK);
        }

        stat.pwcsName = NULL;
        if (!_fDone)
        {
            nts = NtQueryInformationFile(_h, &iosb, &fi,
                                         sizeof(FILE_STANDARD_INFORMATION),
                                         FileStandardInformation);
            if (!NT_SUCCESS(nts))
                ssErr(EH_Err, NtStatusToScode(nts));

            ssChk(CoMemAlloc(sizeof(CONTENTS_STREAM),
                             (void **)&stat.pwcsName));
            wcscpy(stat.pwcsName, CONTENTS_STREAM);
        
            stat.type = STGTY_STREAM;
            stat.cbSize = *(ULARGE_INTEGER *)&fi.EndOfFile;
            stat.mtime.dwLowDateTime = stat.mtime.dwHighDateTime = 0;
            stat.atime.dwLowDateTime = stat.atime.dwHighDateTime = 0;
            stat.ctime.dwLowDateTime = stat.ctime.dwHighDateTime = 0;
            stat.grfMode = 0;
            stat.grfLocksSupported = 0;
            stat.clsid = CLSID_NULL;
            stat.grfStateBits = 0;
            stat.reserved /* BUGBUG dwStgFmt */ = 0;

            rgelt[0] = stat;
            if (pceltFetched)
                *pceltFetched = 1;
        
            _fDone = TRUE;
        
            if (celt > 1)
                sc = S_FALSE;
            else
                sc = S_OK;
        }
        else
        {
            if (pceltFetched)
                *pceltFetched = 0;
            sc = S_FALSE;
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        if (stat.pwcsName)
            ssVerSucc(CoMemFree(stat.pwcsName));
        sc = HRESULT_FROM_NT(GetExceptionCode());
    }
        
    ssDebugOut((DEB_TRACE, "Out COfsFileEnum::Next => 0x%lX\n", sc));
EH_Err:
    return ssResult(sc);
}

//+--------------------------------------------------------------
//
//  Member:     COfsFileEnum::Skip, public
//
//  Synopsis:   Skips N entries from an iterator
//
//  Arguments:  [celt] - Count of elements
//
//  Returns:    Appropriate status code
//
//  History:    21-Jul-93       DrewB   Created
//
//---------------------------------------------------------------

STDMETHODIMP COfsFileEnum::Skip(ULONG celt)
{
    SCODE sc;

    ssDebugOut((DEB_TRACE, "In  COfsFileEnum::Skip:%p(%lu)\n", this, celt));
    
    ssChk(Validate());

    if (celt > 0)
    {
        if (_fDone)
            sc = S_FALSE;
        else
            _fDone = TRUE;
    }

    ssDebugOut((DEB_TRACE, "Out COfsFileEnum::Skip\n"));
EH_Err:
    return ssResult(sc);
}

//+--------------------------------------------------------------
//
//  Member:     COfsFileEnum::Reset, public
//
//  Synopsis:   Rewinds the iterator
//
//  Returns:    Appropriate status code
//
//  History:    21-Jul-93       DrewB   Created
//
//---------------------------------------------------------------

STDMETHODIMP COfsFileEnum::Reset(void)
{
    SCODE sc;

    ssDebugOut((DEB_TRACE, "In  COfsFileEnum::Reset:%p()\n", this));

    ssChk(Validate());
    _fDone = FALSE;

    ssDebugOut((DEB_TRACE, "Out COfsFileEnum::Reset\n"));
EH_Err:
    return ssResult(sc);
}

//+--------------------------------------------------------------
//
//  Member:     COfsFileEnum::Clone, public
//
//  Synopsis:   Clones this iterator
//
//  Arguments:  [ppenm] - Clone return
//
//  Returns:    Appropriate status code
//
//  Modifies:   [ppenm]
//
//  History:    21-Jul-93       DrewB   Created
//
//---------------------------------------------------------------

STDMETHODIMP COfsFileEnum::Clone(IEnumSTATSTG **ppenm)
{
    SCODE sc;
    SafeCOfsFileEnum pfe;

    ssDebugOut((DEB_TRACE, "In  COfsFileEnum::Clone:%p(%p)\n", this, ppenm));

    ssChk(Validate());
    
    pfe.Attach(new COfsFileEnum());
    ssMem((COfsFileEnum *)pfe);
    ssAssert(_h != NULL);
    ssChk(pfe->InitFromHandle(_h, _fDone));
    TRANSFER_INTERFACE(pfe, IEnumSTATSTG, ppenm);
        
    ssDebugOut((DEB_TRACE, "Out COfsFileEnum::Clone => %p\n", *ppenm));
EH_Err:
    return ssResult(sc);
}
