#ifndef _INC_DSKQUOTA_DETAILS_H
#define _INC_DSKQUOTA_DETAILS_H
///////////////////////////////////////////////////////////////////////////////
/*  File: details.h

    Description: Declaration for class DetailsView.
        This is a complex class but don't be intimidated by it.
        Much of the functionality has been layered in private subclasses
        so that the scope of any individual piece is minimized.


    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    08/20/96    Initial creation.                                    BrianAu
    12/06/96    Removed INLINE from message handler methods.         BrianAu
                It's just too hard to debug when they're inline.
    05/28/97    Major changes.                                       BrianAu
                - Added "User Finder".
                - Added promotion of selected item to front of
                  name resolution queue.
                - Improved name resolution status reporting through
                  listview.
                - Moved drag/drop and report generation code
                  from dragdrop.cpp and reptgen.cpp into the
                  DetailsView class.  DetailsView now implements
                  IDataObject, IDropSource and IDropTarget instead
                  of deferring implementation to secondary objects.
                  dragdrop.cpp and reptgen.cpp have been dropped
                  from the project.
                - Added support for CF_HDROP and private import/
                  export clipboard formats.
                - Added import/export functionality.
    07/28/97    Removed export support for CF_HDROP.  Replaced       BrianAu
                with FileContents and FileGroupDescriptor.  Import
                from CF_HDROP is still supported.
                Added Import Source object hierarchy.
*/
///////////////////////////////////////////////////////////////////////////////
#ifndef _INC_DSKQUOTA_H
#   include "dskquota.h"
#endif
#ifndef _INC_DSKQUOTA_CONTROL_H
#   include "control.h"
#endif
#ifndef _INC_DSKQUOTA_UNDO_H
#   include "undo.h"
#endif
#ifndef _INC_DSKQUOTA_FORMAT_H
#   include "format.h"
#endif
#ifndef _INC_DSKQUOTA_PROGRESS_H
#   include "progress.h"
#endif

//
// Custom messages for this implementation.
//
#define WM_MAINWINDOW_CREATED         (WM_USER + 1)
#define WM_ADD_USER_TO_DETAILS_VIEW   (WM_USER + 2)
#define WM_DEL_USER_FROM_DETAILS_VIEW (WM_USER + 3)


//
// Structure containing column definition data for the listview.
//
struct DV_COLDATA
{
    int fmt;
    int cx;
    DWORD idMsgText;
    int iColId;
};


//
// Listview report item structure.
// Used for obtaining text/numeric data for a given item in the listview
// for purposes of generating a drag-drop data source.
//
typedef struct
{
    DWORD  fType;
    LPTSTR pszText;
    UINT   cchMaxText;
    DWORD  dwValue;
    double dblValue;
} LV_REPORT_ITEM, *PLV_REPORT_ITEM;

//
// Listview Report Item (LVRI) type constants (fType)
// These indicate what type of data is requested for a LV_REPORT_ITEM and
// also what type of data is provided in LV_REPORT_ITEM.  A caller of
// DetailsView::GetReportItem provides an LV_REPORT_ITEM that acts as the
// communication mechanism between the caller and the DetailsView.  The
// caller fills in the fType member indicating what format of information
// is desired for that row/col item.  The request may be any one of the
// following constants:
//
//      LVRI_TEXT   = Would like data in text format if possible.
//      LVRI_INT    = Would like data in integer format if possible.
//      LVRI_REAL   = Would like data in floating point format if possible.
//      LVRI_NUMBER = Would like data in either INT or REAL format if possible.
//
// This value in fType is merely a hint.  If the data can't be provided in the
// requested format, the next best format is supplied.  Upon return, the fType
// flag may be modified to indicate the actual format of the data returned.
// This value may be either LVRI_TEXT, LVRI_INT or LVRI_REAL.  LVRI_NUMBER is
// only used for hinting by the caller.
//
const DWORD LVRI_TEXT   = 0x00000001;
const DWORD LVRI_INT    = 0x00000002;
const DWORD LVRI_REAL   = 0x00000004;
const DWORD LVRI_NUMBER = (LVRI_INT | LVRI_REAL);

//
// Structure of "ListViewState" information stored in registry per-user.
// Note that we include the structure size and the screen width/height
// to validate the information when we read it from the registry.  If the
// structure size has changed, we don't trust the data and use defaults.
// If the screen size has changed, we use defaults.
//
//
//
// WARNING: I really don't like this but...
//          The size of the rgcxCol[] member must be at least as large
//          as the value of DetailsView::idCol_Last.  Because of the
//          order dependencies of the LV_STATE_INFO and DetailsView
//          structures, I can't use idCol_Last in this declaration.
//          If you have to add a new column and change the value of
//          idCol_Last, make sure the size of rgcxCol[] is adjusted
//          appropriately.  Also adjust rgColIndices[].
//
typedef struct
{
    WORD cb;                   // Count of bytes in structure.
    WORD wVersion;             // Version of state info (for upgrades).
    LONG cxScreen;             // Screen width.
    LONG cyScreen;             // Screen height.
    LONG cx;                   // Width of window (pixels).
    LONG cy;                   // Height of window (pixels).
    WORD fToolBar       :  1;  // Toolbar visible?
    WORD fStatusBar     :  1;  // Status bar visible?
    WORD fShowFolder    :  1;  // Folder column visible?
    WORD iLastColSorted :  4;  // Current sort column.
    WORD fSortDirection :  1;  // 0 = Ascending, 1 = Descending.
    WORD fReserved      :  8;  // Unused bits.
    INT  rgcxCol[8];           // Width of each column (pixels).
    INT  rgColIndices[8];      // Order of subitems in listview.

} LV_STATE_INFO, *PLV_STATE_INFO;

//
// Increment this if you make a change that causes problems with
// state info saved for existing users.  It will cause us to invalidate
// any existing state information and to use defaults.  It may cancel
// any user's existing preferences but at least the view will look OK.
//
const WORD wLV_STATE_INFO_VERSION = 3;

//
// This class maps our column ids (idCol_XXXX) to a listview column
// index (SubItem).
//
class ColumnMap
{
    private:
        INT *m_pMap;
        UINT m_cMapSize;

        //
        // Prevent copying.
        //
        ColumnMap(const ColumnMap&);
        void operator = (const ColumnMap&);

    public:
        ColumnMap(UINT cMapSize);
        ~ColumnMap(VOID);

        INT SubItemToId(INT iSubItem) const;
        INT IdToSubItem(INT iColId) const;
        VOID RemoveId(INT iSubItem);
        VOID InsertId(INT iSubItem, INT iColId);
};


class DetailsView : public IDiskQuotaEvents,
                    public IDropSource,
                    public IDropTarget,
                    public IDataObject
{
    private:
        //
        // DetailsView::Finder ------------------------------------------------
        //
        //
        // This class implements the "find a user" feature.
        // 1. "Attaches" to the "find" combo box in the toolbar by subclassing
        //     that combo box window.
        // 2. Invokes the "Find User" dialog on command.
        // 3. Repositions the listview highlight bar on a user if found.
        // 4. Maintains an MRU list for populating the toolbar and dialog
        //    combo boxes.
        //
        class Finder
        {
            public:
                Finder(DetailsView& DetailsView, INT cMaxMru);
                VOID ConnectToolbarCombo(HWND hwndToolbarCombo);
                VOID InvokeFindDialog(HWND hwndParent);

                static INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
                static LRESULT CALLBACK ToolbarComboSubClassWndProc(HWND, UINT, WPARAM, LPARAM);

            private:
                HWND m_hwndToolbarCombo;    // Combo box in toolbar.
                INT  m_cMaxComboEntries;    // Max entries allowed in combo MRU.
                DetailsView& m_DetailsView; // Reference to associated details view.
                WNDPROC m_pfnOldToolbarComboWndProc; // Saved wnd proc address.

                VOID AddNameToCombo(HWND hwndCombo, LPCTSTR pszName, INT cMaxEntries);
                BOOL UserNameEntered(HWND hwndCombo);
                VOID FillDialogCombo(HWND hwndComboSrc, HWND hwndComboDest);

                //
                // Prevent copy.
                //
                Finder(const Finder& rhs);
                Finder& operator = (const Finder& rhs);
        };

        //
        // DetailsView::Importer ----------------------------------------------
        //
        class Importer
        {
            public:
                Importer(DetailsView& DV);
                ~Importer(VOID);

                HRESULT Import(IDataObject *pIDataObject);
                HRESULT Import(const FORMATETC& fmt, const STGMEDIUM& medium);
                HRESULT Import(LPCTSTR pszFilePath);
                HRESULT Import(HDROP hDrop);

            private:
                //
                // DetailsView::Importer::AnySource ---------------------------
                //
                // This small hierarchy of "Source" classes is here to insulate
                // the import process from the import source.  There are two
                // basic forms of import source data; OLE stream and memory-
                // mapped file.  So that we only have one function that actually
                // contains the import logic, this layer of abstraction insulates
                // that import function from any differences between streams
                // and simple memory blocks.
                // Instead of calling Import(pStream) or Import(pbBlock), a
                // client uses Import(Source(pIStream)) or Import(Source(pbBlock)).
                // The Source object uses the virtual constructor technique to
                // create the correct object for the input source.  Each
                // descendant of AnySource implements the single Read() function
                // to read data from it's specific source.
                //
                class AnySource
                {
                    public:
                        AnySource(VOID) { }
                        virtual ~AnySource(VOID) { }
                        virtual HRESULT Read(LPVOID pvOut, ULONG cb, ULONG *pcbRead) = 0;

                    private:
                        //
                        // Prevent copy.
                        //
                        AnySource(const AnySource& rhs);
                        AnySource& operator = (const AnySource& rhs);
                };

                //
                // DetailsView::Importer::StreamSource ------------------------
                //
                class StreamSource : public AnySource
                {
                    public:
                        StreamSource(IStream *pStm);
                        virtual ~StreamSource(VOID);

                        virtual HRESULT Read(LPVOID pvOut, ULONG cb, ULONG *pcbRead);

                    private:
                        IStream *m_pStm;

                        //
                        // Prevent copy.
                        //
                        StreamSource(const StreamSource& rhs);
                        StreamSource& operator = (const StreamSource& rhs);
                };

                //
                // DetailsView::Importer::MemorySource ------------------------
                //
                class MemorySource : public AnySource
                {
                    public:
                        MemorySource(LPBYTE pb, ULONG cbMax);
                        virtual ~MemorySource(VOID) { };

                        virtual HRESULT Read(LPVOID pvOut, ULONG cb, ULONG *pcbRead);

                    private:
                        LPBYTE m_pb;
                        ULONG  m_cbMax;

                        //
                        // Prevent copy.
                        //
                        MemorySource(const MemorySource& rhs);
                        MemorySource& operator = (const MemorySource& rhs);
                };

                //
                // DetailsView::Importer::Source ------------------------------
                //
                class Source
                {
                    public:
                        Source(IStream *pStm);
                        Source(LPBYTE pb, ULONG cbMax);

                        virtual ~Source(VOID);

                        virtual HRESULT Read(LPVOID pvOut, ULONG cb, ULONG *pcbRead);

                    private:
                        AnySource *m_pTheSource;

                        //
                        // Prevent copy.
                        //
                        Source(const Source& rhs);
                        Source& operator = (const Source& rhs);
                };


                //
                // These two import functions are the real workers.
                // All other import functions eventually end up at
                // Import(Source& ) which calls Import(pbSid, Threshold, Limit)
                // to import each user record.
                //
                HRESULT Import(Source& source);
                HRESULT Import(LPBYTE pbSid, LONGLONG llQuotaThreshold,
                                             LONGLONG llQuotaLimit);

                VOID Destroy(VOID);
                HWND GetTopmostWindow(VOID);

                DetailsView&   m_DV;
                BOOL           m_bUserCancelled;   // User cancelled import.
                BOOL           m_bPromptOnReplace; // Prompt user when replacing record?
                ProgressDialog m_dlgProgress;      // Progress dialog.
                HWND           m_hwndParent;       // Parent HWND for any UI elements.
                INT            m_cImported;        // Number of records imported.

                //
                // Prevent copy.
                //
                Importer(const Importer& rhs);
                Importer& operator = (const Importer& rhs);
        };

        //
        // DetailsView::DataObject --------------------------------------------
        //
        class DataObject
        {
            public:
                DataObject(DetailsView& DV);
                ~DataObject(VOID);

                HRESULT IsFormatSupported(FORMATETC *pFormatEtc);
                HRESULT RenderData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium);

                static VOID SetFormatEtc(FORMATETC& fe,
                                         CLIPFORMAT cfFormat,
                                         DWORD tymed,
                                         DWORD dwAspect = DVASPECT_CONTENT,
                                         DVTARGETDEVICE *ptd = NULL,
                                         LONG lindex = -1);

                static LPSTR WideToAnsi(LPCWSTR pszTextW);

                static const INT   CF_FORMATS_SUPPORTED;
                static LPCWSTR     SZ_EXPORT_STREAM_NAME;
                static LPCTSTR     SZ_EXPORT_CF_NAME;
                static const DWORD EXPORT_STREAM_VERSION;

                LPFORMATETC  m_rgFormats;            // Array of supported formats.
                DWORD        m_cFormats;             // Number of supported formats.
                static CLIPFORMAT m_CF_Csv;                // Comma-separated fields format.
                static CLIPFORMAT m_CF_RichText;           // RTF format.
                static CLIPFORMAT m_CF_NtDiskQuotaExport;  // Internal fmt for import/export.
                static CLIPFORMAT m_CF_FileGroupDescriptor;// Used by shell for drop to folder.
                static CLIPFORMAT m_CF_FileContents;       // Used by shell for drop to folder.

            private:
                //
                // DetailsView::DataObject::Renderer --------------------------
                //
                class Renderer
                {
                    protected:
                        //
                        // DetailsView::DataObject::Renderer::Stream ----------
                        //
                        class Stream
                        {
                            private:
                                IStream *m_pStm;

#ifdef CLIPBOARD_DEBUG_OUTPUT

                                IStorage *m_pStgDbgOut; // For debugging clipboard output.
                                IStream  *m_pStmDbgOut; // For debugging clipboard output.

#endif  // CLIPBOARD_DEBUG_OUTPUT
                                //
                                // Prevent copy.
                                //
                                Stream(const Stream& rhs);
                                Stream& operator = (const Stream& rhs);

                            public:
                                Stream(IStream *pStm = NULL);
                                ~Stream(VOID);

                                VOID SetStream(IStream *pStm);
                                IStream *GetStream(VOID)
                                    { return m_pStm; }

                                VOID Write(LPBYTE pbData, UINT cbData);
                                VOID Write(LPCSTR pszTextA);
                                VOID Write(LPCWSTR pszTextW);
                                VOID Write(BYTE bData);
                                VOID Write(CHAR chDataA);
                                VOID Write(WCHAR chDataW);
                                VOID Write(DWORD dwData);
                                VOID Write(double dblData);
                        };


                        DetailsView& m_DV;   // Details view is source of data.
                        Stream       m_Stm;  // Stream on which report is writtn.

                        virtual VOID Begin(INT cRows, INT cCols) { }
                        virtual VOID AddTitle(LPCWSTR pszTitleW) { }
                        virtual VOID BeginHeaders(VOID) { }
                        virtual VOID AddHeader(LPCWSTR pszHeaderW) { }
                        virtual VOID AddHeaderSep(VOID) { }
                        virtual VOID EndHeaders(VOID) { }
                        virtual VOID BeginRow(VOID) { }
                        virtual VOID AddRowColData(INT iRow, INT idCol) { }
                        virtual VOID AddRowColSep(VOID) { }
                        virtual VOID EndRow(VOID) { }
                        virtual VOID End(VOID) { }

                        //
                        // Prevent copy.
                        //
                        Renderer(const Renderer& rhs);
                        Renderer& operator = (const Renderer& rhs);


                    public:
                        Renderer(DetailsView& DV)
                            : m_DV(DV) { }

                        virtual ~Renderer(VOID) { }

                        virtual VOID Render(IStream *pStm);
                };

                //
                // DetailsView::DataObject::Renderer_UNICODETEXT --------------
                //
                class Renderer_UNICODETEXT : public Renderer
                {
                    private:
                        //
                        // Prevent copy.
                        //
                        Renderer_UNICODETEXT(const Renderer_UNICODETEXT& rhs);
                        Renderer_UNICODETEXT& operator = (const Renderer_UNICODETEXT& rhs);

                    protected:
                        virtual VOID AddTitle(LPCWSTR pszTitleW);

                        virtual VOID AddHeader(LPCWSTR pszHeaderW)
                            { m_Stm.Write(pszHeaderW); }

                        virtual VOID AddHeaderSep(VOID)
                            { m_Stm.Write(L'\t'); }

                        virtual VOID EndHeaders(VOID)
                            { m_Stm.Write(L'\r'); m_Stm.Write(L'\n'); }

                        virtual VOID AddRowColData(INT iRow, INT idCol);

                        virtual VOID AddRowColSep(VOID)
                            { m_Stm.Write(L'\t'); }

                        virtual VOID EndRow(VOID)
                            { m_Stm.Write(L'\r'); m_Stm.Write(L'\n'); }

                    public:
                        Renderer_UNICODETEXT(DetailsView& DV)
                            : Renderer(DV) { }

                        virtual ~Renderer_UNICODETEXT(VOID) { }
                };

                //
                // DetailsView::DataObject::Renderer_TEXT ---------------------
                //
                class Renderer_TEXT : public Renderer_UNICODETEXT
                {
                    private:
                        //
                        // Prevent copy.
                        //
                        Renderer_TEXT(const Renderer_TEXT& rhs);
                        Renderer_TEXT& operator = (const Renderer_TEXT& rhs);

                    protected:
                        virtual VOID AddTitle(LPCWSTR pszTitleW);

                        virtual VOID AddHeader(LPCWSTR pszHeaderW);

                        virtual VOID AddHeaderSep(VOID)
                            { m_Stm.Write('\t'); }

                        virtual VOID EndHeaders(VOID)
                            { m_Stm.Write('\r'); m_Stm.Write('\n'); }

                        virtual VOID AddRowColData(INT iRow, INT idCol);

                        virtual VOID AddRowColSep(VOID)
                            { m_Stm.Write('\t'); }

                        virtual VOID EndRow(VOID)
                            { m_Stm.Write('\r'); m_Stm.Write('\n'); }

                    public:
                        Renderer_TEXT(DetailsView& DV)
                            : Renderer_UNICODETEXT(DV) { }

                        virtual ~Renderer_TEXT(VOID) { }
                };


                //
                // DetailsView::DataObject::Renderer_Csv ----------------------
                //
                class Renderer_Csv : public Renderer_TEXT
                {
                    private:
                        //
                        // Prevent copy.
                        //
                        Renderer_Csv(const Renderer_Csv& rhs);
                        Renderer_Csv& operator = (const Renderer_Csv& rhs);

                    protected:
                        virtual VOID AddHeaderSep(VOID)
                            { m_Stm.Write(','); }

                        virtual VOID AddRowColSep(VOID)
                            { m_Stm.Write(','); }

                    public:
                        Renderer_Csv(DetailsView& DV)
                            : Renderer_TEXT(DV) { }

                        virtual ~Renderer_Csv(VOID) { }
                };

                //
                // DetailsView::DataObject::Renderer_RTF ----------------------
                //
                class Renderer_RTF : public Renderer
                {
                    private:
                        INT m_cCols;

                        LPSTR DoubleBackslashes(LPSTR pszText);

                        //
                        // Prevent copy.
                        //
                        Renderer_RTF(const Renderer_RTF& rhs);
                        Renderer_RTF& operator = (const Renderer_RTF& rhs);

                    protected:
                        virtual VOID Begin(INT cRows, INT cCols);

                        virtual VOID AddTitle(LPCWSTR pszTitleW);

                        virtual VOID BeginHeaders(VOID);

                        virtual VOID AddHeader(LPCWSTR pszHeaderW);

                        virtual VOID AddHeaderSep(VOID)
                            { AddRowColSep(); }

                        virtual VOID EndHeaders(VOID)
                            { m_Stm.Write("\\row "); }

                        virtual VOID BeginRow(VOID)
                            { BeginHeaderOrRow();
                              AddCellDefs(); }

                        virtual VOID AddRowColData(INT iRow, INT idCol);

                        virtual VOID AddRowColSep(VOID)
                            { m_Stm.Write("\\cell "); }

                        virtual VOID EndRow(VOID)
                            { m_Stm.Write("\\row "); }

                        virtual VOID End(VOID)
                            { m_Stm.Write(" \\pard \\widctlpar \\par }"); }

                        virtual VOID BeginHeaderOrRow(VOID);

                        virtual VOID AddCellDefs(VOID);


                    public:
                        Renderer_RTF(DetailsView& DV)
                            : Renderer(DV),
                              m_cCols(0) { }

                        virtual ~Renderer_RTF(VOID) { }
                };


                //
                // DetailsView::DataObject::Renderer_Export -------------------
                //
                class Renderer_Export : public Renderer
                {
                    private:
                        //
                        // Prevent copy.
                        //
                        Renderer_Export(const Renderer_Export& rhs);
                        Renderer_Export& operator = (const Renderer_Export& rhs);

                    protected:
                        virtual VOID Render(IStream *pStm);

                        virtual VOID Begin(INT cRows, INT cCols);

                        virtual VOID AddBinaryRecord(INT iRow);

                        virtual VOID End(VOID) { }

                    public:
                        Renderer_Export(DetailsView& DV)
                            : Renderer(DV) { }

                        virtual ~Renderer_Export(VOID) { }
                };

                //
                // DetailsView::DataObject::Renderer_FileGroupDescriptor ------
                //
                class Renderer_FileGroupDescriptor : public Renderer
                {
                    private:
                        //
                        // Prevent copy.
                        //
                        Renderer_FileGroupDescriptor(const Renderer_FileGroupDescriptor& rhs);
                        Renderer_FileGroupDescriptor& operator = (const Renderer_FileGroupDescriptor& rhs);

                    protected:
                        virtual VOID Begin(INT cRows, INT cCols);

                    public:
                        Renderer_FileGroupDescriptor(DetailsView& DV)
                            : Renderer(DV) { }

                        virtual ~Renderer_FileGroupDescriptor(VOID) { };
                };


                //
                // DetailsView::DataObject::Renderer_FileContents -------------
                //
                class Renderer_FileContents : public Renderer_Export
                {
                    private:
                        //
                        // Prevent copy.
                        //
                        Renderer_FileContents(const Renderer_FileContents& rhs);
                        Renderer_FileContents& operator = (const Renderer_FileContents& rhs);

                    protected:

                    public:
                        Renderer_FileContents(DetailsView& DV)
                            : Renderer_Export(DV) { }

                        virtual ~Renderer_FileContents(VOID) { };
                };

                //
                // DetailsView::DataObject private member variables.
                //
                IStorage    *m_pStg;                 // Storage pointer.
                IStream     *m_pStm;                 // Stream pointer.
                DetailsView& m_DV;

                //
                // Private functions to help with the rendering process.
                //
                HRESULT CreateRenderStream(DWORD tymed, IStream **ppStm);
                HRESULT RenderData(IStream *pStm, CLIPFORMAT cf);

                //
                // Prevent copy.
                //
                DataObject(const DataObject& rhs);
                DataObject& operator = (const DataObject& rhs);
        };

        //
        // DetailsView::DropSource --------------------------------------------
        //
        class DropSource
        {
            public:
                DropSource(DWORD grfKeyState)
                    : m_grfKeyState(grfKeyState) { }

                ~DropSource(VOID) { }
                DWORD m_grfKeyState;  // "Key" used to start drag/drop.

            private:

                //
                // Prevent copying.
                //
                DropSource(const DropSource&);
                void operator = (const DropSource&);
        };

        //
        // DetailsView::DropTarget --------------------------------------------
        //
        class DropTarget
        {
            public:
                DropTarget(DWORD grfKeyState)
                    : m_grfKeyState(grfKeyState),
                      m_pIDataObject(NULL) { }

                ~DropTarget(VOID) { };

                DWORD m_grfKeyState;  // "Key" used to start drag/drop.
                IDataObject *m_pIDataObject; // Ptr received through DragEnter.

            private:
                //
                // Prevent copying.
                //
                DropTarget(const DropTarget&);
                void operator = (const DropTarget&);
        };


        LONG               m_cRef;
        PointerList        m_UserList;         // List of user objects.
        HWND               m_hwndMain;         // Main window.
        HWND               m_hwndListView;     // Listview window.
        HWND               m_hwndStatusBar;    // Status bar.
        HWND               m_hwndToolBar;      // Tool bar.
        HWND               m_hwndToolbarCombo; // "Find User" combo box.
        HWND               m_hwndListViewToolTip;   // Tool tip window.
        HWND               m_hwndHeader;       // Listview header control.
        HACCEL             m_hKbdAccel;        // Accelerator table.
        WNDPROC            m_lpfnLVWndProc;    // We subclass the LV control.
        PDISKQUOTA_CONTROL m_pQuotaControl;    // Ptr to quota controller.
        Finder            *m_pUserFinder;      // For locating users in listview.
        UndoList          *m_pUndoList;        // For "undoing" mods and deletes.
        ColumnMap          m_ColMap;           // ColId to iSubItem map.
        DropSource         m_DropSource;
        DropTarget         m_DropTarget;
        DataObject        *m_pDataObject;
        CVolumeID          m_idVolume;
        CString            m_strVolumeDisplayName;
        CString            m_strAccountUnresolved;
        CString            m_strAccountUnavailable;
        CString            m_strAccountDeleted;
        CString            m_strAccountUnknown;
        CString            m_strAccountInvalid;
        CString            m_strNoLimit;
        CString            m_strNotApplicable;
        CString            m_strStatusOK;
        CString            m_strStatusWarning;
        CString            m_strStatusOverlimit;
        CString            m_strDispText;
        LPDATAOBJECT       m_pIDataObjectOnClipboard;
        POINT              m_ptMouse;          // For hit-testing tooltips.
        DWORD              m_dwEventCookie;    // Event sink cookie.
        INT                m_iLastItemHit;     // Last item mouse was over.
        INT                m_iLastColSorted;
        DWORD              m_fSortDirection;   // 0 = Ascending, 1 = Descending
        CRITICAL_SECTION   m_csAsyncUpdate;
        LV_STATE_INFO      m_lvsi;             // Persistent lv state info.
        BOOL               m_bMenuActive;      // Is a menu active?
        BOOL               m_bWaitCursor;      // Show wait cursor?
        BOOL               m_bStopLoadingObjects;
        BOOL               m_bDestroyingView;
        static const INT   MAX_FINDMRU_ENTRIES;
        static const INT   CX_TOOLBAR_COMBO;
        static const INT   CY_TOOLBAR_COMBO;


        HRESULT InitializeStaticStrings(VOID);
        HRESULT CreateMainWindow(VOID);
        HRESULT CreateListView(VOID);
        HRESULT CreateStatusBar(VOID);
        HRESULT CreateToolBar(VOID);
        HRESULT CreateListViewToolTip(VOID);
        HRESULT AddColumn(INT iColumn, const DV_COLDATA& ColDes);
        HRESULT RemoveColumn(INT iColumn);
        HRESULT AddImages(VOID);
        HRESULT LoadObjects(VOID);
        HRESULT ReleaseObjects(VOID);
        LRESULT SortObjects(DWORD idColumn, DWORD dwDirection);
        LRESULT Refresh(bool bInvalidateCache = false);
        LRESULT SelectAllItems(VOID);
        LRESULT InvertSelectedItems(VOID);
        LRESULT ShowItemCountInStatusBar(VOID);
        LRESULT ShowMenuTextInStatusBar(DWORD idMenuOption);
        VOID SaveViewStateToRegistry(VOID);
        VOID EnableMenuItem_ArrangeByFolder(BOOL bEnable);
        VOID EnableMenuItem_Undo(BOOL bEnable);
        VOID SetWaitCursor(VOID);
        VOID ClearWaitCursor(VOID);
        VOID Redraw(VOID)
            {
                RedrawWindow(m_hwndMain, NULL, NULL,
                             RDW_ERASE |
                             RDW_FRAME |
                             RDW_INVALIDATE |
                             RDW_ALLCHILDREN |
                             RDW_UPDATENOW);
            }

        VOID RedrawItems(VOID)
        {
            ListView_RedrawItems(m_hwndListView, -1, -1);
            UpdateWindow(m_hwndListView);
        }

        BOOL AddUser(PDISKQUOTA_USER pUser);
        INT  GetUserQuotaState(PDISKQUOTA_USER pUser);
        VOID RegisterAsDropTarget(BOOL bActive);
        bool SingleSelectionIsAdmin(void);

        //
        // Message handlers.
        //
        LRESULT OnNotify(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnSize(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnSetCursor(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnSetFocus(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnDestroy(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnMainWindowCreated(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnCommand(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnCmdViewStatusBar(VOID);
        LRESULT OnCmdViewToolBar(VOID);
        LRESULT OnCmdViewShowFolder(VOID);
        LRESULT OnCmdProperties(VOID);
        LRESULT OnCmdNew(VOID);
        LRESULT OnCmdDelete(VOID);
        LRESULT OnCmdUndo(VOID);
        LRESULT OnCmdFind(VOID);
        LRESULT OnCmdEditCopy(VOID);
        LRESULT OnCmdImport(VOID);
        LRESULT OnCmdExport(VOID);
        LRESULT OnMenuSelect(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnContextMenu(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnHelpAbout(HWND);
        LRESULT OnHelpTopics(HWND);
        LRESULT OnSettingChange(HWND, UINT, WPARAM, LPARAM);
        LRESULT OnLVN_OwnerDataFindItem(NMLVFINDITEM *);
        LRESULT OnLVN_GetDispInfo(LV_DISPINFO *);
        LRESULT OnLVN_GetDispInfo_Text(LV_DISPINFO *, PDISKQUOTA_USER);
        LRESULT OnLVN_GetDispInfo_Image(LV_DISPINFO *, PDISKQUOTA_USER);
        LRESULT OnLVN_ColumnClick(NM_LISTVIEW *);
        LRESULT OnLVN_ItemChanged(NM_LISTVIEW *);
        LRESULT OnLVN_BeginDrag(NM_LISTVIEW *);
        LRESULT OnTTN_NeedText(TOOLTIPTEXT *);
        LRESULT LV_OnTTN_NeedText(TOOLTIPTEXT *);
        LRESULT LV_OnMouseMessages(HWND, UINT, WPARAM, LPARAM);
        BOOL HitTestHeader(int xPos, int yPos);

        INT_PTR ActivateListViewToolTip(BOOL bActivate)
            { return SendMessage(m_hwndListViewToolTip, TTM_ACTIVATE, (WPARAM)bActivate, 0); }

        VOID FocusOnSomething(VOID);
        VOID CleanupAfterAbnormalTermination(VOID);

        INT FindUserByName(LPCTSTR pszUserName, PDISKQUOTA_USER *ppIUser = NULL);
        INT FindUserBySid(LPBYTE pbUserSid, PDISKQUOTA_USER *ppIUser = NULL);
        INT FindUserByObjPtr(PDISKQUOTA_USER pIUser);
        BOOL GotoUserName(LPCTSTR pszUser);

        //
        // Connection point stuff.
        //
        HRESULT ConnectEventSink(VOID);
        HRESULT DisconnectEventSink(VOID);
        IConnectionPoint *GetConnectionPoint(VOID);

        static DWORD ThreadProc(LPVOID);
        static INT CompareItems(LPVOID, LPVOID, LPARAM);
        static HRESULT CalcPctQuotaUsed(PDISKQUOTA_USER, LPDWORD);
        static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
        static LRESULT CALLBACK LVSubClassWndProc(HWND, UINT, WPARAM, LPARAM);

        //
        // Prevent copying.
        //
        DetailsView(const DetailsView&);
        void operator = (const DetailsView&);


    public:
        DetailsView(VOID);
        ~DetailsView(VOID);

        BOOL Initialize(
            const CVolumeID& idVolume);

        CVolumeID GetVolumeID(void) const
            { return m_idVolume; }

        //
        // This is public so other UI elements can use it. (i.e. VolPropPage).
        //
        static HRESULT CreateVolumeDisplayName(
                const CVolumeID& idVolume, // [in] - "C:\" or "\\?\Volume{ <guid> }\"
                CString *pstrDisplayName); // [out] - "My Disk (C:)"
        //
        // If you change the value of idCol_Last, see the note with
        // the LV_STATE_INFO structure above regarding the rgcxCol[] member
        // of LV_STATE_INFO.
        //
        enum ColumnIDs { idCol_Status,
                         idCol_Folder,
                         idCol_Name,
                         idCol_LogonName,
                         idCol_AmtUsed,
                         idCol_Limit,
                         idCol_Threshold,
                         idCol_PctUsed,
                         idCol_Last };

        //
        // IUnknown methods.
        //
        STDMETHODIMP
        QueryInterface(
            REFIID riid,
            LPVOID *ppv);

        STDMETHODIMP_(ULONG)
        AddRef(
            VOID);

        STDMETHODIMP_(ULONG)
        Release(
            VOID);

        //
        // IDiskQuotaEvents method.
        //
        STDMETHODIMP
        OnUserNameChanged(
            PDISKQUOTA_USER pUser);


        //
        // IDropSource methods.
        //
        STDMETHODIMP
        GiveFeedback(
            DWORD dwEffect);

        STDMETHODIMP
        QueryContinueDrag(
            BOOL fEscapePressed,
            DWORD grfKeyState);

        //
        // IDropTarget methods.
        //
        STDMETHODIMP DragEnter(
            IDataObject * pDataObject,
            DWORD grfKeyState,
            POINTL pt,
            DWORD * pdwEffect);

        STDMETHODIMP DragOver(
            DWORD grfKeyState,
            POINTL pt,
            DWORD * pdwEffect);

        STDMETHODIMP DragLeave(
            VOID);

        STDMETHODIMP Drop(
            IDataObject * pDataObject,
            DWORD grfKeyState,
            POINTL pt,
            DWORD * pdwEffect);


        //
        // IDataObject methods.
        //
        STDMETHODIMP
        GetData(
            FORMATETC *pFormatetc,
            STGMEDIUM *pmedium);

        STDMETHODIMP
        GetDataHere(
            FORMATETC *pFormatetc,
            STGMEDIUM *pmedium);

        STDMETHODIMP
        QueryGetData(
            FORMATETC *pFormatetc);

        STDMETHODIMP
        GetCanonicalFormatEtc(
            FORMATETC *pFormatetcIn,
            FORMATETC *pFormatetcOut);

        STDMETHODIMP
        SetData(
            FORMATETC *pFormatetc,
            STGMEDIUM *pmedium,
            BOOL fRelease);

        STDMETHODIMP
        EnumFormatEtc(
            DWORD dwDirection,
            IEnumFORMATETC **ppenumFormatetc);

        STDMETHODIMP
        DAdvise(
            FORMATETC *pFormatetc,
            DWORD advf,
            IAdviseSink *pAdvSink,
            DWORD *pdwConnection);

        STDMETHODIMP
        DUnadvise(
            DWORD dwConnection);

        STDMETHODIMP
        EnumDAdvise(
            IEnumSTATDATA **ppenumAdvise);



        HWND GetHWndMain(VOID)
            { return m_hwndMain; }

        static VOID InitLVStateInfo(PLV_STATE_INFO plvsi);
        static BOOL IsValidLVStateInfo(PLV_STATE_INFO plvsi);

        void GetVolumeDisplayName(CString *pstrName)
            { *pstrName = m_strVolumeDisplayName; }

        UINT GetColumnIds(INT *prgColIds, INT cColIds);

        //
        // Methods for getting drag-drop report data from details view.
        //
        INT GetNextSelectedItemIndex(INT iRow);
        BOOL GetReportItem(UINT iRow, UINT iColId, PLV_REPORT_ITEM pItem);
        VOID GetReportTitle(LPTSTR pszDest, UINT cchDest);
        VOID GetReportColHeader(UINT iColId, LPTSTR pszDest, UINT cchDest);
        UINT GetReportColCount(VOID);
        UINT GetReportRowCount(VOID);
        //
        // These methods are for generating binary "reports" used in exporting
        // user quota information for transfer between volumes.
        //
        UINT GetReportBinaryRecordSize(UINT iRow);
        BOOL GetReportBinaryRecord(UINT iRow, LPBYTE pbRecord, UINT cbRecord);

        //
        // NOTE:  If the requirement for friendship between DetailsView and
        //        DetailsView::Finder exceeds only a few instances, we
        //        might as well grant total friendship to the Finder class.
        //        As long as the instance count is small, I like to keep
        //        the friendship restricted as much as possible.
        //
        // This Finder::DlgProc needs to call DetailsView::GotoUserName.
        //
        friend BOOL Finder::UserNameEntered(HWND);
        //
        // Finder::DlgProc needs access to Details::CY_TOOLBAR_COMBO.
        //
        friend INT_PTR CALLBACK Finder::DlgProc(HWND, UINT, WPARAM, LPARAM);

        friend class Importer;
};



//
// Represents a selection in the listview.
// Objects of this type are used for communicating a selection set to
// a function.  The recpient of the LVSelection object can query it
// to obtain information about the selection.
//
class LVSelection
{
    private:
        HWND m_hwndListView;
        struct ListEntry
        {
            PDISKQUOTA_USER pUser;
            INT iItem;
        };

        StructureList m_List;

        //
        // Prevent copying.
        //
        LVSelection(const LVSelection&);
        void operator = (const LVSelection&);

    public:
        LVSelection(HWND hwndListView)
            : m_hwndListView(hwndListView),
              m_List(sizeof(ListEntry), 10) { }

        LVSelection(VOID)
            : m_hwndListView(NULL),
              m_List(sizeof(ListEntry), 1) { }

        ~LVSelection(VOID) { }

        VOID Add(PDISKQUOTA_USER pUser, INT iItem);
        HWND GetListViewHwnd(VOID)
            { return m_hwndListView; }
        INT Count(VOID)
            { return m_List.Count(); }
        BOOL Retrieve(INT i, PDISKQUOTA_USER *ppUser, INT *piItem);
        BOOL Retrieve(INT i, PDISKQUOTA_USER *ppUser)
            { return Retrieve(i, ppUser, NULL); }
        BOOL Retrieve(INT i, INT *pItem)
            { return Retrieve(i, NULL, pItem); }
        VOID Clear(VOID)
            { m_List.Clear(); }
};




#endif // _INC_DSKQUOTA_DETAILS_H


