1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/volume.cpp 
   3 // Purpose:     wxFSVolume - encapsulates system volume information 
   4 // Author:      George Policello 
   8 // Copyright:   (c) 2002 George Policello 
   9 // Licence:     wxWindows license 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "fsvolume.h" 
  24 #include "wx/wxprec.h" 
  38 #include "wx/hashmap.h" 
  39 #include "wx/dynlib.h" 
  40 #include "wx/arrimpl.cpp" 
  42 #include "wx/volume.h" 
  47 #ifndef SHGFI_ATTRIBUTES 
  48     #define SHGFI_ATTRIBUTES 2048 
  51 #ifndef SFGAO_READONLY 
  52     #define SFGAO_READONLY 0x00040000L 
  55 #ifndef SFGAO_REMOVABLE 
  56     #define SFGAO_REMOVABLE 0x02000000L 
  59 #ifndef SHGFI_DISPLAYNAME 
  60     #define SHGFI_DISPLAYNAME 512 
  64     #define SHGFI_ICON 256 
  67 #ifndef SHGFI_SMALLICON 
  68      #define SHGFI_SMALLICON 1 
  71 #ifndef SHGFI_SHELLICONSIZE 
  72     #define SHGFI_SHELLICONSIZE 4 
  75 #ifndef SHGFI_OPENICON 
  76     #define SHGFI_OPENICON 2 
  79 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
  80 // Dynamic library function defs. 
  81 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
  83 static wxDynamicLibrary s_mprLib
; 
  85 typedef DWORD (WINAPI
* WNetOpenEnumPtr
)(DWORD
, DWORD
, DWORD
, LPNETRESOURCE
, LPHANDLE
); 
  86 typedef DWORD (WINAPI
* WNetEnumResourcePtr
)(HANDLE
, LPDWORD
, LPVOID
, LPDWORD
); 
  87 typedef DWORD (WINAPI
* WNetCloseEnumPtr
)(HANDLE
); 
  89 static WNetOpenEnumPtr s_pWNetOpenEnum
; 
  90 static WNetEnumResourcePtr s_pWNetEnumResource
; 
  91 static WNetCloseEnumPtr s_pWNetCloseEnum
; 
  93 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
  95 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
  96 static long s_cancelSearch 
= FALSE
; 
  98 struct FileInfo 
: public wxObject
 
 100     FileInfo(unsigned flag
=0, wxFSVolumeKind type
=wxFS_VOL_OTHER
) : 
 101         m_flags(flag
), m_type(type
) {} 
 103     wxFSVolumeKind m_type
; 
 105 WX_DECLARE_STRING_HASH_MAP(FileInfo
, FileInfoMap
); 
 106 static FileInfoMap 
s_fileInfo(25); 
 108 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 109 // Other initialization. 
 110 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 112 // already in wx/iconbndl.h 
 113 // WX_DEFINE_OBJARRAY(wxIconArray); 
 116 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 117 // Local helper functions. 
 118 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 120 //============================================================================= 
 121 // Function: GetBasicFlags 
 122 // Purpose: Set basic flags, primarily wxFS_VOL_REMOTE and wxFS_VOL_REMOVABLE. 
 123 // Notes: - Local and mapped drives are mounted by definition.  We have no 
 124 //          way to determine mounted status of network drives, so assume that 
 125 //          all drives are mounted, and let the caller decide otherwise. 
 126 //        - Other flags are 'best guess' from type of drive.  The system will 
 127 //          not report the file attributes with any degree of accuracy. 
 128 //============================================================================= 
 129 static unsigned GetBasicFlags(const wxChar
* filename
) 
 131     unsigned flags 
= wxFS_VOL_MOUNTED
; 
 133     //---------------------------------- 
 134     // 'Best Guess' based on drive type. 
 135     //---------------------------------- 
 137     switch(GetDriveType(filename
)) 
 140         type 
= wxFS_VOL_DISK
; 
 143     case DRIVE_REMOVABLE
: 
 144         flags 
|= wxFS_VOL_REMOVABLE
; 
 145         type 
= wxFS_VOL_FLOPPY
; 
 149         flags 
|= wxFS_VOL_REMOVABLE 
| wxFS_VOL_READONLY
; 
 150         type 
= wxFS_VOL_CDROM
; 
 154         flags 
|= wxFS_VOL_REMOTE
; 
 155         type 
= wxFS_VOL_NETWORK
; 
 158     case DRIVE_NO_ROOT_DIR
: 
 159         flags 
&= ~wxFS_VOL_MOUNTED
; 
 160         type 
= wxFS_VOL_OTHER
; 
 164         type 
= wxFS_VOL_OTHER
; 
 168     //----------------------------------------------------------------------- 
 169     // The following will most likely will not modify anything not set above, 
 170     // and will not work at all for network shares or empty CD ROM drives. 
 171     // But it is a good check if the Win API ever gets better about reporting 
 173     //----------------------------------------------------------------------- 
 176     rc 
= SHGetFileInfo(filename
, 0, &fi
, sizeof(fi
), SHGFI_ATTRIBUTES 
); 
 179         wxLogError(_("Cannot read typename from '%s'!"), filename
); 
 183         if (fi
.dwAttributes 
& SFGAO_READONLY
) 
 184             flags 
|= wxFS_VOL_READONLY
; 
 185         if (fi
.dwAttributes 
& SFGAO_REMOVABLE
) 
 186             flags 
|= wxFS_VOL_REMOVABLE
; 
 192     s_fileInfo
[filename
] = FileInfo(flags
, type
); 
 197 //============================================================================= 
 198 // Function: FilteredAdd 
 199 // Purpose: Add a file to the list if it meets the filter requirement. 
 200 // Notes: - See GetBasicFlags for remarks about the Mounted flag. 
 201 //============================================================================= 
 202 static bool FilteredAdd(wxArrayString
& list
, const wxChar
* filename
,  
 203                         unsigned flagsSet
, unsigned flagsUnset
) 
 206     unsigned flags 
= GetBasicFlags(filename
); 
 208     if (flagsSet 
& wxFS_VOL_MOUNTED 
&& !(flags 
& wxFS_VOL_MOUNTED
)) 
 210     else if (flagsUnset 
& wxFS_VOL_MOUNTED 
&& (flags 
& wxFS_VOL_MOUNTED
)) 
 212     else if (flagsSet 
& wxFS_VOL_REMOVABLE 
&& !(flags 
& wxFS_VOL_REMOVABLE
)) 
 214     else if (flagsUnset 
& wxFS_VOL_REMOVABLE 
&& (flags 
& wxFS_VOL_REMOVABLE
)) 
 216     else if (flagsSet 
& wxFS_VOL_READONLY 
&& !(flags 
& wxFS_VOL_READONLY
)) 
 218     else if (flagsUnset 
& wxFS_VOL_READONLY 
&& (flags 
& wxFS_VOL_READONLY
)) 
 220     else if (flagsSet 
& wxFS_VOL_REMOTE 
&& !(flags 
& wxFS_VOL_REMOTE
)) 
 222     else if (flagsUnset 
& wxFS_VOL_REMOTE 
&& (flags 
& wxFS_VOL_REMOTE
)) 
 225     // Add to the list if passed the filter. 
 232 //============================================================================= 
 233 // Function: BuildListFromNN 
 234 // Purpose: Append or remove items from the list 
 235 // Notes: - There is no way to find all disconnected NN items, or even to find 
 236 //          all items while determining which are connected and not.  So this 
 237 //          function will find either all items or connected items. 
 238 //============================================================================= 
 239 static void BuildListFromNN(wxArrayString
& list
, NETRESOURCE
* pResSrc
,  
 240                             unsigned flagsSet
, unsigned flagsUnset
) 
 245     //----------------------------------------------- 
 246     // Scope may be all drives or all mounted drives. 
 247     //----------------------------------------------- 
 248     unsigned scope 
= RESOURCE_GLOBALNET
; 
 249     if (flagsSet 
& wxFS_VOL_MOUNTED
) 
 250         scope 
= RESOURCE_CONNECTED
; 
 252     //---------------------------------------------------------------------- 
 253     // Enumerate all items, adding only non-containers (ie. network shares). 
 254     // Containers cause a recursive call to this function for their own 
 256     //---------------------------------------------------------------------- 
 257     if (rc 
= s_pWNetOpenEnum(scope
, RESOURCETYPE_DISK
, 0, pResSrc
, &hEnum
), rc 
== NO_ERROR
) 
 261         NETRESOURCE
* pRes 
= (NETRESOURCE
*)malloc(size
); 
 262         memset(pRes
, 0, sizeof(NETRESOURCE
)); 
 263         while (rc 
= s_pWNetEnumResource(hEnum
, &count
, pRes
, &size
), rc 
== NO_ERROR 
|| rc 
== ERROR_MORE_DATA
) 
 268             if (rc 
== ERROR_MORE_DATA
) 
 270                 pRes 
= (NETRESOURCE
*)realloc(pRes
, size
); 
 275                 // Enumerate the container. 
 276                 if (pRes
->dwUsage 
& RESOURCEUSAGE_CONTAINER
) 
 278                     BuildListFromNN(list
, pRes
, flagsSet
, flagsUnset
); 
 281                 // Add the network share. 
 284                     wxString 
filename(pRes
->lpRemoteName
); 
 288                         if (filename
.Last() != '\\') 
 289                             filename
.Append('\\'); 
 291                         // The filter function will not know mounted from unmounted, and neither do we unless 
 292                         // we are iterating using RESOURCE_CONNECTED, in which case they all are mounted. 
 293                         // Volumes on disconnected servers, however, will correctly show as unmounted. 
 294                         FilteredAdd(list
, filename
, flagsSet
, flagsUnset
&~wxFS_VOL_MOUNTED
); 
 295                         if (scope 
== RESOURCE_GLOBALNET
) 
 296                             s_fileInfo
[filename
].m_flags 
&= ~wxFS_VOL_MOUNTED
; 
 304         s_pWNetCloseEnum(hEnum
); 
 308 //============================================================================= 
 309 // Function: CompareFcn 
 310 // Purpose: Used to sort the NN list alphabetically, case insensitive. 
 311 //============================================================================= 
 312 static int CompareFcn(const wxString
& first
, const wxString
& second
) 
 314     return wxStricmp(first
.c_str(), second
.c_str()); 
 317 //============================================================================= 
 318 // Function: BuildRemoteList 
 319 // Purpose: Append Network Neighborhood items to the list. 
 320 // Notes: - Mounted gets transalated into Connected.  FilteredAdd is told 
 321 //          to ignore the Mounted flag since we need to handle it in a weird 
 323 //        - The resulting list is sorted alphabetically. 
 324 //============================================================================= 
 325 static bool BuildRemoteList(wxArrayString
& list
, NETRESOURCE
* pResSrc
,  
 326                             unsigned flagsSet
, unsigned flagsUnset
) 
 328     // NN query depends on dynamically loaded library. 
 329     if (!s_pWNetOpenEnum 
|| !s_pWNetEnumResource 
|| !s_pWNetCloseEnum
) 
 331         wxLogError(_("Failed to load mpr.dll.")); 
 335     // Don't waste time doing the work if the flags conflict. 
 336     if (flagsSet 
& wxFS_VOL_MOUNTED 
&& flagsUnset 
& wxFS_VOL_MOUNTED
) 
 339     //---------------------------------------------- 
 340     // Generate the list according to the flags set. 
 341     //---------------------------------------------- 
 342     BuildListFromNN(list
, pResSrc
, flagsSet
, flagsUnset
); 
 343     list
.Sort(CompareFcn
); 
 345     //------------------------------------------------------------------------- 
 346     // If mounted only is requested, then we only need one simple pass. 
 347     // Otherwise, we need to build a list of all NN volumes and then apply the 
 348     // list of mounted drives to it. 
 349     //------------------------------------------------------------------------- 
 350     if (!(flagsSet 
& wxFS_VOL_MOUNTED
)) 
 353         wxArrayString mounted
; 
 354         BuildListFromNN(mounted
, pResSrc
, flagsSet 
| wxFS_VOL_MOUNTED
, flagsUnset 
& ~wxFS_VOL_MOUNTED
); 
 355         mounted
.Sort(CompareFcn
); 
 357         // apply list from bottom to top to preserve indexes if removing items. 
 358         int iList 
= list
.GetCount()-1; 
 360         for (iMounted 
= mounted
.GetCount()-1; iMounted 
>= 0 && iList 
>= 0; iMounted
--) 
 363             wxString 
all(list
[iList
]); 
 364             wxString 
mount(mounted
[iMounted
]); 
 367                      wxStricmp(list
[iList
].c_str(), mounted
[iMounted
].c_str()), 
 368                    compare 
> 0 && iList 
>= 0) 
 377                 // Found the element.  Remove it or mark it mounted. 
 378                 if (flagsUnset 
& wxFS_VOL_MOUNTED
) 
 381                     s_fileInfo
[list
[iList
]].m_flags 
|= wxFS_VOL_MOUNTED
; 
 392 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 394 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 396 //============================================================================= 
 397 // Function: GetVolumes 
 398 // Purpose: Generate and return a list of all volumes (drives) available. 
 400 //============================================================================= 
 401 wxArrayString 
wxFSVolume::GetVolumes(int flagsSet
, int flagsUnset
) 
 403     InterlockedExchange(&s_cancelSearch
, FALSE
);     // reset 
 405     if (!s_mprLib
.IsLoaded() && s_mprLib
.Load(_T("mpr.dll"))) 
 408         s_pWNetOpenEnum 
= (WNetOpenEnumPtr
)s_mprLib
.GetSymbol(_T("WNetOpenEnumW")); 
 409         s_pWNetEnumResource 
= (WNetEnumResourcePtr
)s_mprLib
.GetSymbol("WNetEnumResourceW"); 
 411         s_pWNetOpenEnum 
= (WNetOpenEnumPtr
)s_mprLib
.GetSymbol(_T("WNetOpenEnumA")); 
 412         s_pWNetEnumResource 
= (WNetEnumResourcePtr
)s_mprLib
.GetSymbol(_T("WNetEnumResourceA")); 
 414         s_pWNetCloseEnum 
= (WNetCloseEnumPtr
)s_mprLib
.GetSymbol(_T("WNetCloseEnum")); 
 419     //------------------------------- 
 420     // Local and mapped drives first. 
 421     //------------------------------- 
 422     // Allocate the required space for the API call. 
 423     size_t chars 
= GetLogicalDriveStrings(0, 0); 
 424     TCHAR
* buf 
= new TCHAR
[chars
+1]; 
 426     // Get the list of drives. 
 427     chars 
= GetLogicalDriveStrings(chars
, buf
); 
 429     // Parse the list into an array, applying appropriate filters. 
 434         FilteredAdd(list
, pVol
, flagsSet
, flagsUnset
); 
 435         pVol 
= pVol 
+ wxStrlen(pVol
) + 1; 
 441     //--------------------------- 
 442     // Network Neighborhood next. 
 443     //--------------------------- 
 445     // not exclude remote and not removable 
 446     if (!(flagsUnset 
& wxFS_VOL_REMOTE
) && 
 447         !(flagsSet 
& wxFS_VOL_REMOVABLE
) 
 450         // The returned list will be sorted alphabetically.  We don't pass 
 451         // our in since we don't want to change to order of the local drives. 
 453         if (BuildRemoteList(nn
, 0, flagsSet
, flagsUnset
)) 
 455             for (size_t idx 
= 0; idx 
< nn
.GetCount(); idx
++) 
 463 //============================================================================= 
 464 // Function: CancelSearch 
 465 // Purpose: Instruct an active search to stop. 
 466 // Notes: - This will only sensibly be called by a thread other than the one 
 467 //          performing the search.  This is the only thread-safe function 
 468 //          provided by the class. 
 469 //============================================================================= 
 470 void wxFSVolume::CancelSearch() 
 472     InterlockedExchange(&s_cancelSearch
, TRUE
); 
 475 //============================================================================= 
 476 // Function: constructor 
 477 // Purpose: default constructor 
 478 //============================================================================= 
 479 wxFSVolume::wxFSVolume() 
 484 //============================================================================= 
 485 // Function: constructor 
 486 // Purpose: constructor that calls Create 
 487 //============================================================================= 
 488 wxFSVolume::wxFSVolume(const wxString
& name
) 
 493 //============================================================================= 
 495 // Purpose: Finds, logs in, etc. to the request volume. 
 496 //============================================================================= 
 497 bool wxFSVolume::Create(const wxString
& name
) 
 507     long rc 
= SHGetFileInfo(m_volName
, 0, &fi
, sizeof(fi
), SHGFI_DISPLAYNAME
); 
 510         wxLogError(_("Cannot read typename from '%s'!"), m_volName
.c_str()); 
 513     m_dispName 
= fi
.szDisplayName
; 
 517     m_icons
.Alloc(wxFS_VOL_ICO_MAX
); 
 520     for (idx 
= 0; idx 
< wxFS_VOL_ICO_MAX
; idx
++) 
 526     return m_isOk 
= TRUE
; 
 529 //============================================================================= 
 531 // Purpose: returns TRUE if the volume is legal. 
 532 // Notes: For fixed disks, it must exist.  For removable disks, it must also 
 533 //        be present.  For Network Shares, it must also be logged in, etc. 
 534 //============================================================================= 
 535 bool wxFSVolume::IsOk() const 
 540 //============================================================================= 
 542 // Purpose: Return the type of the volume. 
 543 //============================================================================= 
 544 wxFSVolumeKind 
wxFSVolume::GetKind() const 
 547         return wxFS_VOL_OTHER
; 
 549     FileInfoMap::iterator itr 
= s_fileInfo
.find(m_volName
); 
 550     if (itr 
== s_fileInfo
.end()) 
 551         return wxFS_VOL_OTHER
; 
 553     return itr
->second
.m_type
; 
 556 //============================================================================= 
 557 // Function: GetFlags 
 558 // Purpose: Return the caches flags for this volume. 
 559 // Notes: - Returns -1 if no flags were cached. 
 560 //============================================================================= 
 561 int wxFSVolume::GetFlags() const 
 566     FileInfoMap::iterator itr 
= s_fileInfo
.find(m_volName
); 
 567     if (itr 
== s_fileInfo
.end()) 
 570     return itr
->second
.m_flags
; 
 575 //============================================================================= 
 577 // Purpose: return the requested icon. 
 578 //============================================================================= 
 579 wxIcon 
wxFSVolume::GetIcon(wxFSIconType type
) const 
 581     wxCHECK_MSG(type 
< (int)m_icons
.GetCount(), wxNullIcon
,  
 582                 _T("Invalid request for icon type!")); 
 583     wxCHECK_MSG( type 
>= 0 && (size_t)type 
< m_icons
.GetCount(), 
 585                  _T("invalid icon index") ); 
 588     if (m_icons
[type
].IsNull()) 
 593         case wxFS_VOL_ICO_SMALL
: 
 594             flags 
= SHGFI_ICON 
| SHGFI_SMALLICON
; 
 597         case wxFS_VOL_ICO_LARGE
: 
 598             flags 
= SHGFI_ICON 
| SHGFI_SHELLICONSIZE
; 
 601         case wxFS_VOL_ICO_SEL_SMALL
: 
 602             flags 
= SHGFI_ICON 
| SHGFI_SMALLICON 
| SHGFI_OPENICON
; 
 605         case wxFS_VOL_ICO_SEL_LARGE
: 
 606             flags 
= SHGFI_ICON 
| SHGFI_SHELLICONSIZE 
| SHGFI_OPENICON
; 
 609         case wxFS_VOL_ICO_MAX
: 
 610             wxFAIL_MSG(_T("wxFS_VOL_ICO_MAX is not valid icon type")); 
 615         long rc 
= SHGetFileInfo(m_volName
, 0, &fi
, sizeof(fi
), flags
); 
 616         m_icons
[type
].SetHICON((WXHICON
)fi
.hIcon
); 
 617         if (!rc 
|| !fi
.hIcon
) 
 618             wxLogError(_("Cannot load icon from '%s'."), m_volName
.c_str()); 
 621     return m_icons
[type
]; 
 626 #endif // wxUSE_FSVOLUME