523 lines
19 KiB
C++
523 lines
19 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: filelist.h
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifndef _INC_CSCVIEW_FILELIST_H
|
|
#define _INC_CSCVIEW_FILELIST_H
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/* File: filelist.h
|
|
|
|
Description: Simplifies the transmission of a list of share and
|
|
associated file names between components of the CSC UI. See
|
|
description further below for details.
|
|
|
|
Classes:
|
|
|
|
CscFilenameList
|
|
CscFilenameList::HSHARE
|
|
CscFilenameList::ShareIter
|
|
CscFilenameList::FileIter
|
|
|
|
Note: This module was written to be used by any part of the CSCUI,
|
|
not just the viewer. Therefore, I don't assume that the
|
|
new operator will throw an exception on allocation failures.
|
|
I don't like all the added code to detect allocation failures
|
|
but it's not reasonable to expect code in the other components
|
|
to become exception-aware with respect to "new" failures.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
11/28/97 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#ifndef _WINDOWS_
|
|
# include <windows.h>
|
|
#endif
|
|
|
|
//
|
|
// This set of classes is designed to transfer a list of network share
|
|
// names and network file names between components of the CSC UI
|
|
// (i.e. wizard, viewer, onestop etc). Data is transferred through
|
|
// a formatted byte buffer that is essentially an opaque blob
|
|
// to both the sender and receiver. The class CscFilenameList
|
|
// was created to prevent the sender and receiver from having
|
|
// to understand the buffer format. The buffer is formatted as follows:
|
|
//
|
|
// +----------------+---------------------------------+
|
|
// | <namelist hdr> | <share descriptors> |
|
|
// +----------------+---------------------------------+
|
|
// | |
|
|
// | |
|
|
// | <share and file names> |
|
|
// | |
|
|
// | |
|
|
// +--------------------------------------------------+
|
|
//
|
|
//
|
|
// Where: <namelist hdr> is a single block of type CSC_NAMELIST_HDR.
|
|
// This block describes the size of the buffer and the
|
|
// share count.
|
|
//
|
|
// <share descriptors> is an array of type CSC_NAMELIST_SHARE_DESC,
|
|
// one for each share in the buffer. Each share descriptor
|
|
// describes the offset to the share name, the offset
|
|
// to the first file name and the number of file names
|
|
// in the buffer. All offsets are byte offsets from the
|
|
// start of the buffer.
|
|
//
|
|
// <share and file names> is an array of TCHARs containing the
|
|
// names of the shares and files stored in the buffer.
|
|
// Each name string is nul-terminated.
|
|
//
|
|
//
|
|
// The following outline describes how I see someone using this feature:
|
|
//
|
|
// 1. Instantiate a CscFilenameList object (no ctor arguments).
|
|
// 2. Call AddShare() whenever a share is to be added.
|
|
// 3. Call AddFile() whenever a file is to be added. Note that
|
|
// saving the HSHARE returned by AddShare() can make file name addition
|
|
// more efficient as it eliminates the need for an internal lookup
|
|
// of the associated share name each time a file name is added.
|
|
//
|
|
// i.e.: CscFilenameList fnl;
|
|
// HSHARE hShare = fnl.AddShare("\\\\server\\share");
|
|
// fnl.AddFile(hShare, "foo.txt");
|
|
// fnl.AddFile(hShare, "bar.txt");
|
|
//
|
|
// is more efficient than...
|
|
//
|
|
// CscFilenameList fnl;
|
|
// fnl.AddFile("\\\\server\\share", "foo.txt");
|
|
// fnl.AddFile("\\\\server\\share", "bar.txt");
|
|
//
|
|
// ...which is slightly more efficient than...
|
|
//
|
|
// CscFilenameList fnl;
|
|
// fnl.AddFile("\\\\server\\share\\foo.txt");
|
|
// fnl.AddFile("\\\\server\\share\\bar.txt");
|
|
//
|
|
// ...although all 3 methods are supported.
|
|
//
|
|
// 4. Once all shares and files are added, call CreateListBuffer() to retrieve
|
|
// the information formatted in a byte buffer. The buffer is allocated
|
|
// on the heap.
|
|
// 5. Pass the buffer address to the desired program component.
|
|
// 6. The receiving component instantiates a CscFilenameList object passing
|
|
// the address of the buffer to the ctor. This initializes the namelist
|
|
// so that it merely references the information in the buffer rather than
|
|
// duplicating the name information in memory. Note that the buffer must
|
|
// remain in memory while this namelist object is in use.
|
|
// 7. The receiving component creates a Share Iterator by calling
|
|
// CreateShareIterator(). The returned iterator enumerates each of the
|
|
// shares contained in the namelist object.
|
|
// 8. The receiving component enumerates the shares (receiving an HSHARE) for
|
|
// each. To get a share's name string, call GetShareName() passing the
|
|
// HSHARE for the desired share.
|
|
// 9. For each share, the recieving component creates a File Iterator by
|
|
// calling CreateFileIterator() passing the HSHARE for the desired share.
|
|
// The returned iterator enumerates each of the file names associated
|
|
// with the share.
|
|
// 10. Once the operation is complete, FreeListBuffer is called to delete
|
|
// the byte buffer created by CreateListBuffer().
|
|
//
|
|
//
|
|
// The following example illustrates this process:
|
|
//
|
|
//
|
|
// void Foo(void)
|
|
// {
|
|
// CscFilenameList fnl; // Namelist object.
|
|
// CscFilenameList::HSHARE hShare; // Share handle.
|
|
//
|
|
// // Add a share and some files
|
|
//
|
|
// fnl.AddShare(TEXT("\\\\worf\\ntspecs"), &hShare);
|
|
// fnl.AddFile(hShare, TEXT("foo.txt"));
|
|
// fnl.AddFile(hShare, TEXT("bar.txt"));
|
|
//
|
|
// // Add another share and some files.
|
|
//
|
|
// fnl.AddShare(TEXT("\\\\msoffice\\products"), &hShare);
|
|
// fnl.AddFile(hShare, TEXT("word.doc"));
|
|
// fnl.AddFile(hShare, TEXT("excel.doc"));
|
|
// fnl.AddFile(hShare, TEXT("powerpoint.doc"));
|
|
// fnl.AddFile(hShare, TEXT("access.doc"));
|
|
//
|
|
// // Add another share and more files using the less-efficient
|
|
// // method. It's valid, just less efficient.
|
|
//
|
|
// fnl.AddFile(TEXT("\\\\performance\\poor"), TEXT("turtle.doc"));
|
|
// fnl.AddFile(TEXT("\\\\performance\\poor"), TEXT("snail.doc"));
|
|
// fnl.AddFile(TEXT("\\\\performance\\poor"), TEXT("inchworm.doc"));
|
|
//
|
|
// // Create the byte buffer from the namelist and pass it to
|
|
// // the receiving component.
|
|
//
|
|
// LPBYTE pbBuffer = fnl.CreateListBuffer();
|
|
// Bar(pbBuffer);
|
|
//
|
|
// // Delete the byte buffer when we're done.
|
|
//
|
|
// FreeListBuffer(pbBuffer);
|
|
// }
|
|
//
|
|
//
|
|
// void Bar(LPBYTE pbBuffer)
|
|
// {
|
|
// // Create a new namelist object from the byte buffer.
|
|
//
|
|
// CscFileNameList fnl(pbBuffer);
|
|
//
|
|
// // Create a share iterator.
|
|
//
|
|
// CscFilenameList::ShareIter si = fnl.CreateShareIterator();
|
|
// CscFilenameList::HSHARE hShare;
|
|
//
|
|
// // Iterate over the shares in the namelist collection.
|
|
//
|
|
// while(si.Next(&hShare))
|
|
// {
|
|
// _tprintf(TEXT("Share..: \"%s\"\n"), fnl.GetShareName(hShare));
|
|
//
|
|
// // Create a file iterator for the share.
|
|
//
|
|
// CscFilenameList::FileIter fi = fl.CreateFileIterator(hShare);
|
|
// LPCTSTR pszFile;
|
|
//
|
|
// // Iterate over the filenames associated with the share.
|
|
//
|
|
// while(pszFile = fi.Next())
|
|
// {
|
|
// _tprintf(TEXT("\tFile..: \"%s\"\n"), pszFile);
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// [brianau - 11/28/97]
|
|
//
|
|
|
|
//
|
|
// Namelist byte buffer header block (offset 0).
|
|
//
|
|
typedef struct
|
|
{
|
|
DWORD cbSize;
|
|
DWORD cShares;
|
|
|
|
} CSC_NAMELIST_HDR, *PCSC_NAMELIST_HDR;
|
|
|
|
//
|
|
// Namelist byte buffer share descriptor block. Array (one per share)
|
|
// starting at offset 12 (immediately following the header block).
|
|
//
|
|
typedef struct
|
|
{
|
|
DWORD cbOfsShareName;
|
|
DWORD cbOfsFileNames;
|
|
DWORD cFiles;
|
|
|
|
} CSC_NAMELIST_SHARE_DESC, *PCSC_NAMELIST_SHARE_DESC;
|
|
|
|
|
|
|
|
class CscFilenameList
|
|
{
|
|
private:
|
|
class Share;
|
|
|
|
public:
|
|
class ShareIter;
|
|
class FileIter;
|
|
class HSHARE;
|
|
|
|
// --------------------------------------------------------------------
|
|
// CscFilenameList::HSHARE
|
|
//
|
|
// Share "handle" to communicate the identity of an internal "share"
|
|
// object with the client without exposing the share object directly.
|
|
// The client just knows an HSHARE. Clients get one as the return
|
|
// value from AddShare().
|
|
//
|
|
class HSHARE
|
|
{
|
|
public:
|
|
HSHARE(void);
|
|
HSHARE(const HSHARE& rhs);
|
|
HSHARE& operator = (const HSHARE& rhs);
|
|
~HSHARE(void) { }
|
|
|
|
bool operator ! ()
|
|
{ return NULL == m_pShare; }
|
|
|
|
private:
|
|
//
|
|
// Private so only we can create meaninful HSHARE objects.
|
|
//
|
|
HSHARE(Share *pShare)
|
|
: m_pShare(pShare) { }
|
|
|
|
Share *m_pShare; // ptr to the actual share object.
|
|
|
|
friend class CscFilenameList;
|
|
friend class ShareIter;
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
// CscFilenameList::FileIter
|
|
//
|
|
// Iterator for enumerating each file name associated with a
|
|
// particular share. Clients create one using CreateFileIterator().
|
|
//
|
|
class FileIter
|
|
{
|
|
public:
|
|
FileIter(void);
|
|
~FileIter(void) { }
|
|
FileIter(const FileIter& rhs);
|
|
FileIter& operator = (const FileIter& rhs);
|
|
|
|
LPCTSTR Next(void);
|
|
void Reset(void);
|
|
|
|
private:
|
|
FileIter(const Share *pShare);
|
|
|
|
const Share *m_pShare; // ptr to associated share object.
|
|
int m_iFile; // current file iteration index.
|
|
|
|
friend class CscFilenameList;
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
// CscFilenameList::ShareIter
|
|
//
|
|
// Iterator for enumerating each share in the namelist collection.
|
|
// Clients create one using CreateShareIterator().
|
|
//
|
|
class ShareIter
|
|
{
|
|
public:
|
|
ShareIter(void);
|
|
ShareIter(const CscFilenameList& fnl);
|
|
~ShareIter(void) { }
|
|
ShareIter(const ShareIter& rhs);
|
|
ShareIter& operator = (const ShareIter& rhs);
|
|
|
|
bool Next(HSHARE *phShare);
|
|
void Reset(void);
|
|
|
|
private:
|
|
const CscFilenameList *m_pfnl; // ptr to filename collection obj.
|
|
int m_iShare; // current share iteration index.
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
// Namelist object public interface.
|
|
//
|
|
// Create an empty namelist collection ready to accept share and
|
|
// file names.
|
|
//
|
|
CscFilenameList(void);
|
|
//
|
|
// Create a namelist collection and initialize it with the contents
|
|
// of a byte buffer created by CreateListBuffer().
|
|
// If bCopy is false, the subsequent namelist object merely references
|
|
// the data in the byte buffer rather than duplicating the namestrings
|
|
// in memory. If bCopy is true, name strings are created as if the
|
|
// names had been added using AddShare() and AddFile(). Note that
|
|
// additional share and file name strings may be added at any time.
|
|
// However, they are added to internal structures and not to the
|
|
// byte buffer. Call CreateListBuffer() to add them to a new byte
|
|
// buffer.
|
|
//
|
|
CscFilenameList(PCSC_NAMELIST_HDR pbNames, bool bCopy);
|
|
~CscFilenameList(void);
|
|
//
|
|
// Add a share name to the collection. Does not create a
|
|
// duplicate share entry if one already exists. Returns a handle
|
|
// the a share object.
|
|
//
|
|
bool AddShare(LPCTSTR pszShare, HSHARE *phShare, bool bCopy = true);
|
|
//
|
|
// Add a file for a share. More efficient to use the first
|
|
// version taking a share handle rather than a share name.
|
|
//
|
|
bool AddFile(HSHARE& hShare, LPCTSTR pszFile, bool bDirectory = false, bool bCopy = true);
|
|
bool AddFile(LPCTSTR pszShare, LPCTSTR pszFile, bool bDirectory = false, bool bCopy = true);
|
|
bool AddFile(LPCTSTR pszFullPath, bool bDirectory = false, bool bCopy = true);
|
|
bool RemoveFile(HSHARE& hShare, LPCTSTR pszFile);
|
|
bool RemoveFile(LPCTSTR pszShare, LPCTSTR pszFile);
|
|
bool RemoveFile(LPCTSTR pszFullPath);
|
|
//
|
|
// Retrieve miscellaneous information about the collection.
|
|
//
|
|
int GetShareCount(void) const;
|
|
int GetFileCount(void) const;
|
|
LPCTSTR GetShareName(HSHARE& hShare) const;
|
|
int GetShareFileCount(HSHARE& hShare) const;
|
|
bool GetShareHandle(LPCTSTR pszShare, HSHARE *phShare) const;
|
|
//
|
|
// Determine if a given share or file exists in the collection.
|
|
// For the FileExists() functions, if bExact is true (the default)
|
|
// only exact character-for-character matches return true. If
|
|
// bExact is false, the filename "\\server\share\dirA\dirB\foo.txt"
|
|
// will match if any of the following four entries exist in the
|
|
// namelist:
|
|
//
|
|
// "\\server\share\dirA\dirB\foo.txt" (exact match)
|
|
// "\\server\share\*" (wildcard match)
|
|
// "\\server\share\dirA\*" (wildcard match)
|
|
// "\\server\share\dirA\dirB\*" (wildcard match)
|
|
//
|
|
bool ShareExists(LPCTSTR pszShare) const;
|
|
bool FileExists(HSHARE& hShare, LPCTSTR pszFile, bool bExact = true) const;
|
|
bool FileExists(LPCTSTR pszShare, LPCTSTR pszFile, bool bExact = true) const;
|
|
bool FileExists(LPCTSTR pszFullPath, bool bExact = true) const;
|
|
|
|
//
|
|
// Create iterators for enumerating collection contents.
|
|
//
|
|
ShareIter CreateShareIterator(void) const;
|
|
FileIter CreateFileIterator(HSHARE& hShare) const;
|
|
//
|
|
// Create/free a byte buffer containing the contents of the collection.
|
|
//
|
|
PCSC_NAMELIST_HDR CreateListBuffer(void) const;
|
|
static void FreeListBuffer(PCSC_NAMELIST_HDR pbNames);
|
|
//
|
|
// Check after initializing object from byte buffer.
|
|
//
|
|
bool IsValid(void) const
|
|
{ return m_bValid; }
|
|
|
|
#ifdef FILELIST_TEST
|
|
void Dump(void) const;
|
|
void DumpListBuffer(PCSC_NAMELIST_HDR pbBuffer) const;
|
|
#endif // FILELIST_TEST
|
|
|
|
|
|
private:
|
|
// --------------------------------------------------------------------
|
|
// CscFilenameList::NamePtr
|
|
//
|
|
// Simple wrapper around a string pointer to add a notion of "ownership".
|
|
// This lets us store a string address as either a pointer to dynamic
|
|
// heap memory (that later must be freed) or the address of a string
|
|
// in a character buffer owned by someone else (owner frees it if
|
|
// necessary).
|
|
//
|
|
class NamePtr
|
|
{
|
|
public:
|
|
NamePtr(void)
|
|
: m_pszName(NULL),
|
|
m_bOwns(false) { }
|
|
|
|
NamePtr(LPCTSTR pszName, bool bCopy);
|
|
~NamePtr(void);
|
|
|
|
NamePtr(NamePtr& rhs);
|
|
NamePtr& operator = (NamePtr& rhs);
|
|
|
|
bool IsValid(void) const
|
|
{ return NULL != m_pszName; }
|
|
|
|
operator LPCTSTR () const
|
|
{ return m_pszName; }
|
|
|
|
private:
|
|
LPCTSTR m_pszName; // address of string.
|
|
bool m_bOwns; // do we need to free it on destruction?
|
|
|
|
friend class CscFilenameList;
|
|
friend class Share;
|
|
};
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// CscFilenameList::Share
|
|
//
|
|
// Represents a share in the namelist collection. It's really just
|
|
// a convenient container for a share name and a list of file names
|
|
// associated with the share.
|
|
//
|
|
class Share
|
|
{
|
|
public:
|
|
Share(LPCTSTR pszShare, bool bCopy = true);
|
|
~Share(void);
|
|
|
|
bool AddFile(LPCTSTR pszFile, bool bDirectory = false, bool bCopy = true);
|
|
bool RemoveFile(LPCTSTR pszFile);
|
|
|
|
int FileCount(void) const
|
|
{ return m_cFiles; }
|
|
|
|
int ByteCount(void) const
|
|
{ return (m_cchShareName + m_cchFileNames) * sizeof(TCHAR); }
|
|
|
|
int Write(LPBYTE pbBufferStart,
|
|
CSC_NAMELIST_SHARE_DESC *pDesc,
|
|
LPTSTR pszBuffer,
|
|
int cchBuffer) const;
|
|
|
|
#ifdef FILELIST_TEST
|
|
void Dump(void) const;
|
|
#endif // FILELIST_TEST
|
|
|
|
private:
|
|
int m_cFiles; // Cnt of files in share.
|
|
int m_cAllocated; // Cnt of share ptrs allocated.
|
|
int m_cchShareName; // Bytes req'd to hold share name.
|
|
int m_cchFileNames; // Bytes req'd to hold file names.
|
|
NamePtr m_pszShareName; // Address of share name string.
|
|
NamePtr *m_rgpszFileNames; // Array of ptrs to file name strings
|
|
static int m_cGrow; // File name array growth increment.
|
|
|
|
int WriteFileNames(LPTSTR pszBuffer, int cchBuffer, DWORD *pcFilesWritten) const;
|
|
int WriteName(LPTSTR pszBuffer, int cchBuffer) const;
|
|
bool GrowFileNamePtrList(void);
|
|
|
|
friend class CscFilenameList;
|
|
friend class FileIter;
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
// Namelist object private members.
|
|
//
|
|
int m_cShares; // How many shares in collection.
|
|
int m_cAllocated; // Allocated size of m_rgpShares[].
|
|
Share **m_rgpShares; // Dynamic array of ptrs to Share objects.
|
|
bool m_bValid; // Ctor completion check.
|
|
static int m_cGrow; // How much to grow array when necessary.
|
|
|
|
//
|
|
// Prevent copy.
|
|
//
|
|
CscFilenameList(const CscFilenameList& rhs);
|
|
CscFilenameList& operator = (const CscFilenameList& rhs);
|
|
|
|
bool GrowSharePtrList(void);
|
|
bool LoadFromBuffer(PCSC_NAMELIST_HDR pbBuffer, bool bCopy);
|
|
|
|
void ParseFullPath(LPTSTR pszFullPath,
|
|
LPTSTR *ppszShare,
|
|
LPTSTR *ppszFile) const;
|
|
|
|
static bool Compare(LPCTSTR pszTemplate, LPCTSTR pszFile, bool *pbExact);
|
|
|
|
friend class ShareIter;
|
|
friend class Share;
|
|
};
|
|
|
|
#endif // _INC_CSCVIEW_FILELIST_H
|
|
|