added wxFSVolume patch from George Policello (untested, unreferenced from the project files yet)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14185 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2002-02-13 21:01:50 +00:00
parent bc7e0c92ad
commit 7183fd726e
3 changed files with 705 additions and 0 deletions

View File

@@ -353,6 +353,7 @@ treectrl.cpp MSW Win32Only
utils.cpp MSW Base,LowLevel utils.cpp MSW Base,LowLevel
utilsexc.cpp MSW Base,LowLevel utilsexc.cpp MSW Base,LowLevel
uuid.cpp MSW OLE uuid.cpp MSW OLE
volume.cpp MSW Base
wave.cpp MSW wave.cpp MSW
window.cpp MSW LowLevel window.cpp MSW LowLevel
@@ -951,6 +952,7 @@ valtext.h WXH
variant.h WXH Base variant.h WXH Base
vector.h WXH Base vector.h WXH Base
version.h WXH Base version.h WXH Base
volume.h WXH Base
wave.h WXH wave.h WXH
wfstream.h WXH Base wfstream.h WXH Base
window.h WXH window.h WXH

122
include/wx/volume.h Normal file
View File

@@ -0,0 +1,122 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/volume.h
// Purpose: wxFSVolume - encapsulates system volume information
// Author: George Policello
// Modified by:
// Created: 28 Jan 02
// RCS-ID: $Id$
// Copyright: (c) 2002 George Policello
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// wxFSVolume represents a volume/drive/mount point in a file system
// ----------------------------------------------------------------------------
#ifndef _WX_FSVOLUME_H_
#define _WX_FSVOLUME_H_
#ifdef __GNUG__
#pragma interface "fsvolume.h"
#endif
// the volume flags
enum
{
// is the volume mounted?
wxFS_VOL_MOUNTED = 0x0001,
// is the volume removable (floppy, CD, ...)?
wxFS_VOL_REMOVABLE = 0x0002,
// read only? (otherwise read write)
wxFS_VOL_READONLY = 0x0004,
// network resources
wxFS_VOL_REMOTE = 0x0008
};
// the volume types
enum wxFSVolumeKind
{
wxFS_VOL_FLOPPY,
wxFS_VOL_DISK,
wxFS_VOL_CDROM,
wxFS_VOL_DVDROM,
wxFS_VOL_NETWORK,
wxFS_VOL_OTHER,
wxFS_VOL_MAX
};
#if wxUSE_GUI
enum wxFSIconType
{
wxFS_VOL_ICO_SMALL = 0,
wxFS_VOL_ICO_LARGE,
wxFS_VOL_ICO_SEL_SMALL,
wxFS_VOL_ICO_SEL_LARGE,
wxFS_VOL_ICO_MAX
};
#endif // wxUSE_GUI
WX_DECLARE_OBJARRAY(wxIcon, wxIconArray);
class WXDLLEXPORT wxFSVolume
{
public:
// return the array containing the names of the volumes
//
// only the volumes with the flags such that
// (flags & flagsSet) == flagsSet && !(flags & flagsUnset)
// are returned (by default, all mounted ones)
static wxArrayString GetVolumes(int flagsSet = wxFS_VOL_MOUNTED,
int flagsUnset = 0);
// stop execution of GetVolumes() called previously (should be called from
// another thread, of course)
static void CancelSearch();
// create the volume object with this name (should be one of those returned
// by GetVolumes()).
wxFSVolume();
wxFSVolume(const wxString& name);
bool Create(const wxString& name);
// accessors
// ---------
// is this a valid volume?
bool IsOk() const;
// kind of this volume?
wxFSVolumeKind GetKind() const;
// flags of this volume?
int GetFlags() const;
// can we write to this volume?
bool IsWritable() const { return !(GetFlags() & wxFS_VOL_READONLY); }
// get the name of the volume and the name which should be displayed to the
// user
wxString GetName() const { return m_volName; }
wxString GetDisplayName() const { return m_dispName; }
#if wxUSE_GUI
wxIcon GetIcon(wxFSIconType type) const;
#endif
// TODO: operatios (Mount(), Unmount(), Eject(), ...)?
private:
wxString m_volName;
wxString m_dispName;
#if wxUSE_GUI
wxIconArray m_icons;
#endif
bool m_isOk;
};
#endif // _WX_FSVOLUME_H_

581
src/msw/volume.cpp Normal file
View File

@@ -0,0 +1,581 @@
///////////////////////////////////////////////////////////////////////////////
// Name: src/msw/volume.cpp
// Purpose: wxFSVolume - encapsulates system volume information
// Author: George Policello
// Modified by:
// Created: 28 Jan 02
// RCS-ID: $Id$
// Copyright: (c) 2002 George Policello
// Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "fsvolume.h"
#endif
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#endif // WX_PRECOMP
#include "wx/dir.h"
#include "wx/hashmap.h"
#include "wx/dynlib.h"
#include "wx/arrimpl.cpp"
#include "wx/volume.h"
// Win32 headers
#include <shlobj.h>
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Dynamic library function defs.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static wxDynamicLibrary s_mprLib;
typedef DWORD (WINAPI* WNetOpenEnumPtr)(DWORD, DWORD, DWORD, LPNETRESOURCE, LPHANDLE);
typedef DWORD (WINAPI* WNetEnumResourcePtr)(HANDLE, LPDWORD, LPVOID, LPDWORD);
typedef DWORD (WINAPI* WNetCloseEnumPtr)(HANDLE);
static WNetOpenEnumPtr s_pWNetOpenEnum;
static WNetEnumResourcePtr s_pWNetEnumResource;
static WNetCloseEnumPtr s_pWNetCloseEnum;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Globals/Statics
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static long s_cancelSearch = FALSE;
struct FileInfo : public wxObject
{
FileInfo(unsigned flag=0, wxFSVolumeKind type=wxFS_VOL_OTHER) :
m_flags(flag), m_type(type) {}
unsigned m_flags;
wxFSVolumeKind m_type;
};
WX_DECLARE_STRING_HASH_MAP(FileInfo, FileInfoMap);
static FileInfoMap s_fileInfo(25);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Other initialization.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
WX_DEFINE_OBJARRAY(wxIconArray);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Local helper functions.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=============================================================================
// Function: GetBasicFlags
// Purpose: Set basic flags, primarily wxFS_VOL_REMOTE and wxFS_VOL_REMOVABLE.
// Notes: - Local and mapped drives are mounted by definition. We have no
// way to determine mounted status of network drives, so assume that
// all drives are mounted, and let the caller decide otherwise.
// - Other flags are 'best guess' from type of drive. The system will
// not report the file attributes with any degree of accuracy.
//=============================================================================
unsigned GetBasicFlags(const char* filename)
{
unsigned flags = wxFS_VOL_MOUNTED;
//----------------------------------
// 'Best Guess' based on drive type.
//----------------------------------
wxFSVolumeKind type;
switch(GetDriveType(filename))
{
case DRIVE_FIXED:
type = wxFS_VOL_DISK;
break;
case DRIVE_REMOVABLE:
flags |= wxFS_VOL_REMOVABLE;
type = wxFS_VOL_FLOPPY;
break;
case DRIVE_CDROM:
flags |= wxFS_VOL_REMOVABLE | wxFS_VOL_READONLY;
type = wxFS_VOL_CDROM;
break;
case DRIVE_REMOTE:
flags |= wxFS_VOL_REMOTE;
type = wxFS_VOL_NETWORK;
break;
case DRIVE_NO_ROOT_DIR:
flags &= ~wxFS_VOL_MOUNTED;
type = wxFS_VOL_OTHER;
break;
default:
type = wxFS_VOL_OTHER;
break;
}
//-----------------------------------------------------------------------
// The following will most likely will not modify anything not set above,
// and will not work at all for network shares or empty CD ROM drives.
// But it is a good check if the Win API ever gets better about reporting
// this information.
//-----------------------------------------------------------------------
SHFILEINFO fi;
long rc;
rc = SHGetFileInfo(filename, 0, &fi, sizeof(fi), SHGFI_ATTRIBUTES );
if (!rc)
{
wxLogError(_("Cannot read typename from '%s'!"), filename);
}
else
{
if (fi.dwAttributes & SFGAO_READONLY)
flags |= wxFS_VOL_READONLY;
if (fi.dwAttributes & SFGAO_REMOVABLE)
flags |= wxFS_VOL_REMOVABLE;
}
//------------------
// Flags are cached.
//------------------
s_fileInfo[filename] = FileInfo(flags, type);
return flags;
} // GetBasicFlags
//=============================================================================
// Function: FilteredAdd
// Purpose: Add a file to the list if it meets the filter requirement.
// Notes: - See GetBasicFlags for remarks about the Mounted flag.
//=============================================================================
bool FilteredAdd(wxArrayString& list, const char* filename, unsigned flagsSet, unsigned flagsUnset)
{
bool accept = TRUE;
unsigned flags = GetBasicFlags(filename);
if (flagsSet & wxFS_VOL_MOUNTED && !(flags & wxFS_VOL_MOUNTED))
accept = FALSE;
else if (flagsUnset & wxFS_VOL_MOUNTED && (flags & wxFS_VOL_MOUNTED))
accept = FALSE;
else if (flagsSet & wxFS_VOL_REMOVABLE && !(flags & wxFS_VOL_REMOVABLE))
accept = FALSE;
else if (flagsUnset & wxFS_VOL_REMOVABLE && (flags & wxFS_VOL_REMOVABLE))
accept = FALSE;
else if (flagsSet & wxFS_VOL_READONLY && !(flags & wxFS_VOL_READONLY))
accept = FALSE;
else if (flagsUnset & wxFS_VOL_READONLY && (flags & wxFS_VOL_READONLY))
accept = FALSE;
else if (flagsSet & wxFS_VOL_REMOTE && !(flags & wxFS_VOL_REMOTE))
accept = FALSE;
else if (flagsUnset & wxFS_VOL_REMOTE && (flags & wxFS_VOL_REMOTE))
accept = FALSE;
// Add to the list if passed the filter.
if (accept)
list.Add(filename);
return accept;
} // FilteredAdd
//=============================================================================
// Function: BuildListFromNN
// Purpose: Append or remove items from the list
// Notes: - There is no way to find all disconnected NN items, or even to find
// all items while determining which are connected and not. So this
// function will find either all items or connected items.
//=============================================================================
void BuildListFromNN(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSet, unsigned flagsUnset)
{
HANDLE hEnum;
int rc;
//-----------------------------------------------
// Scope may be all drives or all mounted drives.
//-----------------------------------------------
unsigned scope = RESOURCE_GLOBALNET;
if (flagsSet & wxFS_VOL_MOUNTED)
scope = RESOURCE_CONNECTED;
//----------------------------------------------------------------------
// Enumerate all items, adding only non-containers (ie. network shares).
// Containers cause a recursive call to this function for their own
// enumeration.
//----------------------------------------------------------------------
if (rc = s_pWNetOpenEnum(scope, RESOURCETYPE_DISK, 0, pResSrc, &hEnum), rc == NO_ERROR)
{
unsigned long count = 1;
unsigned long size = 256;
NETRESOURCE* pRes = (NETRESOURCE*)malloc(size);
memset(pRes, 0, sizeof(NETRESOURCE));
while (rc = s_pWNetEnumResource(hEnum, &count, pRes, &size), rc == NO_ERROR || rc == ERROR_MORE_DATA)
{
if (s_cancelSearch)
break;
if (rc == ERROR_MORE_DATA)
{
pRes = (NETRESOURCE*)realloc(pRes, size);
count = 1;
}
else if (count == 1)
{
// Enumerate the container.
if (pRes->dwUsage & RESOURCEUSAGE_CONTAINER)
{
BuildListFromNN(list, pRes, flagsSet, flagsUnset);
}
// Add the network share.
else
{
wxString filename(pRes->lpRemoteName);
if (filename.Len())
{
if (filename.Last() != '\\')
filename.Append('\\');
// The filter function will not know mounted from unmounted, and neither do we unless
// we are iterating using RESOURCE_CONNECTED, in which case they all are mounted.
// Volumes on disconnected servers, however, will correctly show as unmounted.
FilteredAdd(list, filename, flagsSet, flagsUnset&~wxFS_VOL_MOUNTED);
if (scope == RESOURCE_GLOBALNET)
s_fileInfo[filename].m_flags &= ~wxFS_VOL_MOUNTED;
}
}
}
else if (count == 0)
break;
}
free(pRes);
s_pWNetCloseEnum(hEnum);
}
} // BuildListFromNN
//=============================================================================
// Function: CompareFcn
// Purpose: Used to sort the NN list alphabetically, case insensitive.
//=============================================================================
static int CompareFcn(const wxString& first, const wxString& second)
{
return stricmp(first.c_str(), second.c_str());
} // CompareFcn
//=============================================================================
// Function: BuildRemoteList
// Purpose: Append Network Neighborhood items to the list.
// Notes: - Mounted gets transalated into Connected. FilteredAdd is told
// to ignore the Mounted flag since we need to handle it in a weird
// way manually.
// - The resulting list is sorted alphabetically.
//=============================================================================
bool BuildRemoteList(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSet, unsigned flagsUnset)
{
// NN query depends on dynamically loaded library.
if (!s_pWNetOpenEnum || !s_pWNetEnumResource || !s_pWNetCloseEnum)
{
wxLogError(_("Failed to load mpr.dll."));
return FALSE;
}
// Don't waste time doing the work if the flags conflict.
if (flagsSet & wxFS_VOL_MOUNTED && flagsUnset & wxFS_VOL_MOUNTED)
return FALSE;
//----------------------------------------------
// Generate the list according to the flags set.
//----------------------------------------------
BuildListFromNN(list, pResSrc, flagsSet, flagsUnset);
list.Sort(CompareFcn);
//-------------------------------------------------------------------------
// If mounted only is requested, then we only need one simple pass.
// Otherwise, we need to build a list of all NN volumes and then apply the
// list of mounted drives to it.
//-------------------------------------------------------------------------
if (!(flagsSet & wxFS_VOL_MOUNTED))
{
// generate.
wxArrayString mounted;
BuildListFromNN(mounted, pResSrc, flagsSet | wxFS_VOL_MOUNTED, flagsUnset & ~wxFS_VOL_MOUNTED);
mounted.Sort(CompareFcn);
// apply list from bottom to top to preserve indexes if removing items.
int iList = list.GetCount()-1;
int iMounted;
for (iMounted = mounted.GetCount()-1; iMounted >= 0 && iList >= 0; iMounted--)
{
int compare;
wxString all(list[iList]);
wxString mount(mounted[iMounted]);
while (compare = stricmp(list[iList], mounted[iMounted]), compare > 0 && iList >= 0)
{
iList--;
all = list[iList];
}
if (compare == 0)
{
// Found the element. Remove it or mark it mounted.
if (flagsUnset & wxFS_VOL_MOUNTED)
list.Remove(iList);
else
s_fileInfo[list[iList]].m_flags |= wxFS_VOL_MOUNTED;
}
iList--;
}
}
return TRUE;
} // BuildRemoteList
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// wxFSVolume
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//=============================================================================
// Function: GetVolumes
// Purpose: Generate and return a list of all volumes (drives) available.
// Notes:
//=============================================================================
wxArrayString wxFSVolume::GetVolumes(int flagsSet, int flagsUnset)
{
InterlockedExchange(&s_cancelSearch, FALSE); // reset
if (!s_mprLib.IsLoaded() && s_mprLib.Load(_T("mpr.dll")))
{
#ifdef UNICODE
s_pWNetOpenEnum = (WNetOpenEnumPtr)s_mprLib.GetSymbol(_T("WNetOpenEnumW"));
s_pWNetEnumResource = (WNetEnumResourcePtr)s_mprLib.GetSymbol("WNetEnumResourceW");
#else
s_pWNetOpenEnum = (WNetOpenEnumPtr)s_mprLib.GetSymbol(_T("WNetOpenEnumA"));
s_pWNetEnumResource = (WNetEnumResourcePtr)s_mprLib.GetSymbol(_T("WNetEnumResourceA"));
#endif
s_pWNetCloseEnum = (WNetCloseEnumPtr)s_mprLib.GetSymbol(_T("WNetCloseEnum"));
}
wxArrayString list;
//-------------------------------
// Local and mapped drives first.
//-------------------------------
// Allocate the required space for the API call.
size_t chars = GetLogicalDriveStrings(0, 0);
TCHAR* buf = new TCHAR[chars+1];
// Get the list of drives.
chars = GetLogicalDriveStrings(chars, buf);
// Parse the list into an array, applying appropriate filters.
TCHAR *pVol;
pVol = buf;
while (*pVol)
{
FilteredAdd(list, pVol, flagsSet, flagsUnset);
pVol = pVol + _tcslen(pVol) + 1;
}
// Cleanup.
delete[] buf;
//---------------------------
// Network Neighborhood next.
//---------------------------
// not exclude remote and not removable
if (!(flagsUnset & wxFS_VOL_REMOTE) &&
!(flagsSet & wxFS_VOL_REMOVABLE)
)
{
// The returned list will be sorted alphabetically. We don't pass
// our in since we don't want to change to order of the local drives.
wxArrayString nn;
if (BuildRemoteList(nn, 0, flagsSet, flagsUnset))
{
int idx;
for (idx = 0; idx < nn.GetCount(); idx++)
list.Add(nn[idx]);
}
}
return list;
} // GetVolumes
//=============================================================================
// Function: CancelSearch
// Purpose: Instruct an active search to stop.
// Notes: - This will only sensibly be called by a thread other than the one
// performing the search. This is the only thread-safe function
// provided by the class.
//=============================================================================
void wxFSVolume::CancelSearch()
{
InterlockedExchange(&s_cancelSearch, TRUE);
} // CancelSearch
//=============================================================================
// Function: constructor
// Purpose: default constructor
//=============================================================================
wxFSVolume::wxFSVolume()
{
m_isOk = FALSE;
} // wxVolume
//=============================================================================
// Function: constructor
// Purpose: constructor that calls Create
//=============================================================================
wxFSVolume::wxFSVolume(const wxString& name)
{
Create(name);
} // wxVolume
//=============================================================================
// Function: Create
// Purpose: Finds, logs in, etc. to the request volume.
//=============================================================================
bool wxFSVolume::Create(const wxString& name)
{
// assume fail.
m_isOk = FALSE;
// supplied.
m_volName = name;
// Display name.
SHFILEINFO fi;
long rc = SHGetFileInfo(m_volName, 0, &fi, sizeof(fi), SHGFI_DISPLAYNAME);
if (!rc)
{
wxLogError(_("Cannot read typename from '%s'!"), m_volName);
return m_isOk;
}
m_dispName = fi.szDisplayName;
#ifdef wxUSE_GUI
m_icons.Alloc(wxFS_VOL_ICO_MAX);
int idx;
wxIcon null;
for (idx = 0; idx < wxFS_VOL_ICO_MAX; idx++)
m_icons.Add(null);
#endif
// all tests passed.
return m_isOk = TRUE;
} // Create
//=============================================================================
// Function: IsOk
// Purpose: returns TRUE if the volume is legal.
// Notes: For fixed disks, it must exist. For removable disks, it must also
// be present. For Network Shares, it must also be logged in, etc.
//=============================================================================
bool wxFSVolume::IsOk() const
{
return m_isOk;
} // IsOk
//=============================================================================
// Function: GetKind
// Purpose: Return the type of the volume.
//=============================================================================
wxFSVolumeKind wxFSVolume::GetKind() const
{
if (!m_isOk)
return wxFS_VOL_OTHER;
FileInfoMap::iterator itr = s_fileInfo.find(m_volName);
if (itr == s_fileInfo.end())
return wxFS_VOL_OTHER;
return itr->second.m_type;
}
//=============================================================================
// Function: GetFlags
// Purpose: Return the caches flags for this volume.
// Notes: - Returns -1 if no flags were cached.
//=============================================================================
int wxFSVolume::GetFlags() const
{
if (!m_isOk)
return -1;
FileInfoMap::iterator itr = s_fileInfo.find(m_volName);
if (itr == s_fileInfo.end())
return -1;
return itr->second.m_flags;
} // GetFlags
#ifdef wxUSE_GUI
//=============================================================================
// Function: GetIcon
// Purpose: return the requested icon.
//=============================================================================
wxIcon wxFSVolume::GetIcon(wxFSIconType type) const
{
wxASSERT(type < m_icons.GetCount());
if (type >= m_icons.GetCount())
{
wxLogError(_("Invalid request for icon type!"));
wxIcon null;
return null;
}
// Load on demand.
if (m_icons[type].IsNull())
{
unsigned flags = 0;
switch (type)
{
case wxFS_VOL_ICO_SMALL:
flags = SHGFI_ICON | SHGFI_SMALLICON;
break;
case wxFS_VOL_ICO_LARGE:
flags = SHGFI_ICON | SHGFI_SHELLICONSIZE;
break;
case wxFS_VOL_ICO_SEL_SMALL:
flags = SHGFI_ICON | SHGFI_SMALLICON | SHGFI_OPENICON;
break;
case wxFS_VOL_ICO_SEL_LARGE:
flags = SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_OPENICON;
break;
}
SHFILEINFO fi;
long rc = SHGetFileInfo(m_volName, 0, &fi, sizeof(fi), flags);
m_icons[type].SetHICON((WXHICON)fi.hIcon);
if (!rc || !fi.hIcon)
wxLogError(_("Cannot load icon from '%s'."), m_volName);
}
return m_icons[type];
} // GetIcon
#endif // wxUSE_GUI