]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/volume.cpp
Fix assert when creating wxBitmapButton without a valid bitmap in wxMSW.
[wxWidgets.git] / src / msw / volume.cpp
index dacb7542a257fcbf07ec5482231c0da8f2684e78..3ea20ccae4a7c4083df78632a96d5acf68ca5c5f 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     28 Jan 02
 // RCS-ID:      $Id$
 // Copyright:   (c) 2002 George Policello
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
 // ============================================================================
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "fsvolume.h"
-#endif
-
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
     #pragma hdrstop
 #endif
 
+#if wxUSE_FSVOLUME
+
+#include "wx/volume.h"
+
 #ifndef WX_PRECOMP
-#include <wx/icon.h>
-#include <wx/intl.h>
+    #if wxUSE_GUI
+        #include "wx/icon.h"
+    #endif
+    #include "wx/intl.h"
+    #include "wx/log.h"
+    #include "wx/hashmap.h"
+    #include "wx/filefn.h"
 #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
+// some compilers require including <windows.h> before <shellapi.h> so do it
+// even if this is not necessary with most of them
+#include "wx/msw/wrapwin.h"
+#include <shellapi.h>
 #include <shlobj.h>
+#include "wx/msw/missing.h"
+
+#if wxUSE_BASE
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 // Dynamic library function defs.
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
+#if wxUSE_DYNLIB_CLASS
 static wxDynamicLibrary s_mprLib;
+#endif
 
 typedef DWORD (WINAPI* WNetOpenEnumPtr)(DWORD, DWORD, DWORD, LPNETRESOURCE, LPHANDLE);
 typedef DWORD (WINAPI* WNetEnumResourcePtr)(HANDLE, LPDWORD, LPVOID, LPDWORD);
@@ -61,20 +71,31 @@ static WNetCloseEnumPtr s_pWNetCloseEnum;
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 static long s_cancelSearch = FALSE;
 
-struct FileInfo : public wxObject
+struct FileInfo
 {
     FileInfo(unsigned flag=0, wxFSVolumeKind type=wxFS_VOL_OTHER) :
         m_flags(flag), m_type(type) {}
+
+    FileInfo(const FileInfo& other) { *this = other; }
+    FileInfo& operator=(const FileInfo& other)
+    {
+        m_flags = other.m_flags;
+        m_type = other.m_type;
+        return *this;
+    }
+
     unsigned m_flags;
     wxFSVolumeKind m_type;
 };
 WX_DECLARE_STRING_HASH_MAP(FileInfo, FileInfoMap);
-static FileInfoMap s_fileInfo(25);
+// Cygwin bug (?) destructor for global s_fileInfo is called twice...
+static FileInfoMap& GetFileInfoMap()
+{
+    static FileInfoMap s_fileInfo(25);
 
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-// Other initialization.
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-WX_DEFINE_OBJARRAY(wxIconArray);
+    return s_fileInfo;
+}
+#define s_fileInfo (GetFileInfoMap())
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 // Local helper functions.
@@ -89,7 +110,7 @@ WX_DEFINE_OBJARRAY(wxIconArray);
 //        - 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)
+static unsigned GetBasicFlags(const wxChar* filename)
 {
     unsigned flags = wxFS_VOL_MOUNTED;
 
@@ -129,17 +150,19 @@ unsigned GetBasicFlags(const char* filename)
     }
 
     //-----------------------------------------------------------------------
-    // The following will most likely will not modify anything not set above,
+    // The following 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 );
+    long rc = SHGetFileInfo(filename, 0, &fi, sizeof(fi), SHGFI_ATTRIBUTES);
     if (!rc)
     {
-        wxLogError(_("Cannot read typename from '%s'!"), filename);
+        // this error is not fatal, so don't show a message to the user about
+        // it, otherwise it would appear every time a generic directory picker
+        // dialog is used and there is a connected network drive
+        wxLogLastError(wxT("SHGetFileInfo"));
     }
     else
     {
@@ -162,27 +185,28 @@ unsigned GetBasicFlags(const char* filename)
 // 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)
+static bool FilteredAdd(wxArrayString& list, const wxChar* filename,
+                        unsigned flagsSet, unsigned flagsUnset)
 {
-    bool accept = TRUE;
+    bool accept = true;
     unsigned flags = GetBasicFlags(filename);
 
     if (flagsSet & wxFS_VOL_MOUNTED && !(flags & wxFS_VOL_MOUNTED))
-        accept = FALSE;
+        accept = false;
     else if (flagsUnset & wxFS_VOL_MOUNTED && (flags & wxFS_VOL_MOUNTED))
-        accept = FALSE;
+        accept = false;
     else if (flagsSet & wxFS_VOL_REMOVABLE && !(flags & wxFS_VOL_REMOVABLE))
-        accept = FALSE;
+        accept = false;
     else if (flagsUnset & wxFS_VOL_REMOVABLE && (flags & wxFS_VOL_REMOVABLE))
-        accept = FALSE;
+        accept = false;
     else if (flagsSet & wxFS_VOL_READONLY && !(flags & wxFS_VOL_READONLY))
-        accept = FALSE;
+        accept = false;
     else if (flagsUnset & wxFS_VOL_READONLY && (flags & wxFS_VOL_READONLY))
-        accept = FALSE;
+        accept = false;
     else if (flagsSet & wxFS_VOL_REMOTE && !(flags & wxFS_VOL_REMOTE))
-        accept = FALSE;
+        accept = false;
     else if (flagsUnset & wxFS_VOL_REMOTE && (flags & wxFS_VOL_REMOTE))
-        accept = FALSE;
+        accept = false;
 
     // Add to the list if passed the filter.
     if (accept)
@@ -198,7 +222,8 @@ bool FilteredAdd(wxArrayString& list, const char* filename, unsigned flagsSet, u
 //          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)
+static void BuildListFromNN(wxArrayString& list, NETRESOURCE* pResSrc,
+                            unsigned flagsSet, unsigned flagsUnset)
 {
     HANDLE hEnum;
     int rc;
@@ -217,8 +242,8 @@ void BuildListFromNN(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
     //----------------------------------------------------------------------
     if (rc = s_pWNetOpenEnum(scope, RESOURCETYPE_DISK, 0, pResSrc, &hEnum), rc == NO_ERROR)
     {
-        unsigned long count = 1;
-        unsigned long size = 256;
+        DWORD count = 1;
+        DWORD 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)
@@ -244,7 +269,18 @@ void BuildListFromNN(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
                 {
                     wxString filename(pRes->lpRemoteName);
 
-                    if (filename.Len())
+                    // if the drive is unavailable, FilteredAdd() can hang for
+                    // a long time and, moreover, its failure appears to be not
+                    // cached so this will happen every time we use it, so try
+                    // a much quicker wxDirExists() test (which still hangs but
+                    // for much shorter time) for locally mapped drives first
+                    // to try to avoid this
+                    if ( pRes->lpLocalName &&
+                            *pRes->lpLocalName &&
+                                !wxDirExists(pRes->lpLocalName) )
+                        continue;
+
+                    if (!filename.empty())
                     {
                         if (filename.Last() != '\\')
                             filename.Append('\\');
@@ -252,7 +288,7 @@ void BuildListFromNN(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
                         // 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);
+                        FilteredAdd(list, filename.wx_str(), flagsSet, flagsUnset&~wxFS_VOL_MOUNTED);
                         if (scope == RESOURCE_GLOBALNET)
                             s_fileInfo[filename].m_flags &= ~wxFS_VOL_MOUNTED;
                     }
@@ -272,7 +308,7 @@ void BuildListFromNN(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
 //=============================================================================
 static int CompareFcn(const wxString& first, const wxString& second)
 {
-    return stricmp(first.c_str(), second.c_str());
+    return wxStricmp(first.c_str(), second.c_str());
 } // CompareFcn
 
 //=============================================================================
@@ -283,18 +319,19 @@ static int CompareFcn(const wxString& first, const wxString& second)
 //          way manually.
 //        - The resulting list is sorted alphabetically.
 //=============================================================================
-bool BuildRemoteList(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSet, unsigned flagsUnset)
+static 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;
+        return false;
     }
 
     // Don't waste time doing the work if the flags conflict.
     if (flagsSet & wxFS_VOL_MOUNTED && flagsUnset & wxFS_VOL_MOUNTED)
-        return FALSE;
+        return false;
 
     //----------------------------------------------
     // Generate the list according to the flags set.
@@ -315,15 +352,16 @@ bool BuildRemoteList(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
         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--)
+        ssize_t iList = list.GetCount()-1;
+        for (ssize_t 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)
+            while (compare =
+                     wxStricmp(list[iList].c_str(), mounted[iMounted].c_str()),
+                   compare > 0 && iList >= 0)
             {
                 iList--;
                 all = list[iList];
@@ -334,7 +372,7 @@ bool BuildRemoteList(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
             {
                 // Found the element.  Remove it or mark it mounted.
                 if (flagsUnset & wxFS_VOL_MOUNTED)
-                    list.Remove(iList);
+                    list.RemoveAt(iList);
                 else
                     s_fileInfo[list[iList]].m_flags |= wxFS_VOL_MOUNTED;
 
@@ -344,7 +382,7 @@ bool BuildRemoteList(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
         }
     }
 
-    return TRUE;
+    return true;
 } // BuildRemoteList
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -356,21 +394,23 @@ bool BuildRemoteList(wxArrayString& list, NETRESOURCE* pResSrc, unsigned flagsSe
 // Purpose: Generate and return a list of all volumes (drives) available.
 // Notes:
 //=============================================================================
-wxArrayString wxFSVolume::GetVolumes(int flagsSet, int flagsUnset)
+wxArrayString wxFSVolumeBase::GetVolumes(int flagsSet, int flagsUnset)
 {
-    InterlockedExchange(&s_cancelSearch, FALSE);     // reset
+    ::InterlockedExchange(&s_cancelSearch, FALSE);     // reset
 
-    if (!s_mprLib.IsLoaded() && s_mprLib.Load(_T("mpr.dll")))
+#if wxUSE_DYNLIB_CLASS
+    if (!s_mprLib.IsLoaded() && s_mprLib.Load(wxT("mpr.dll")))
     {
 #ifdef UNICODE
-        s_pWNetOpenEnum = (WNetOpenEnumPtr)s_mprLib.GetSymbol(_T("WNetOpenEnumW"));
-        s_pWNetEnumResource = (WNetEnumResourcePtr)s_mprLib.GetSymbol("WNetEnumResourceW");
+        s_pWNetOpenEnum = (WNetOpenEnumPtr)s_mprLib.GetSymbol(wxT("WNetOpenEnumW"));
+        s_pWNetEnumResource = (WNetEnumResourcePtr)s_mprLib.GetSymbol(wxT("WNetEnumResourceW"));
 #else
-        s_pWNetOpenEnum = (WNetOpenEnumPtr)s_mprLib.GetSymbol(_T("WNetOpenEnumA"));
-        s_pWNetEnumResource = (WNetEnumResourcePtr)s_mprLib.GetSymbol(_T("WNetEnumResourceA"));
+        s_pWNetOpenEnum = (WNetOpenEnumPtr)s_mprLib.GetSymbol(wxT("WNetOpenEnumA"));
+        s_pWNetEnumResource = (WNetEnumResourcePtr)s_mprLib.GetSymbol(wxT("WNetEnumResourceA"));
 #endif
-        s_pWNetCloseEnum = (WNetCloseEnumPtr)s_mprLib.GetSymbol(_T("WNetCloseEnum"));
+        s_pWNetCloseEnum = (WNetCloseEnumPtr)s_mprLib.GetSymbol(wxT("WNetCloseEnum"));
     }
+#endif
 
     wxArrayString list;
 
@@ -378,11 +418,11 @@ wxArrayString wxFSVolume::GetVolumes(int flagsSet, int flagsUnset)
     // Local and mapped drives first.
     //-------------------------------
     // Allocate the required space for the API call.
-    size_t chars = GetLogicalDriveStrings(0, 0);
+    const DWORD chars = GetLogicalDriveStrings(0, NULL);
     TCHAR* buf = new TCHAR[chars+1];
 
     // Get the list of drives.
-    chars = GetLogicalDriveStrings(chars, buf);
+    GetLogicalDriveStrings(chars, buf);
 
     // Parse the list into an array, applying appropriate filters.
     TCHAR *pVol;
@@ -425,25 +465,25 @@ wxArrayString wxFSVolume::GetVolumes(int flagsSet, int flagsUnset)
 //          performing the search.  This is the only thread-safe function
 //          provided by the class.
 //=============================================================================
-void wxFSVolume::CancelSearch()
+void wxFSVolumeBase::CancelSearch()
 {
-    InterlockedExchange(&s_cancelSearch, TRUE);
+    ::InterlockedExchange(&s_cancelSearch, TRUE);
 } // CancelSearch
 
 //=============================================================================
 // Function: constructor
 // Purpose: default constructor
 //=============================================================================
-wxFSVolume::wxFSVolume()
+wxFSVolumeBase::wxFSVolumeBase()
 {
-    m_isOk = FALSE;
+    m_isOk = false;
 } // wxVolume
 
 //=============================================================================
 // Function: constructor
 // Purpose: constructor that calls Create
 //=============================================================================
-wxFSVolume::wxFSVolume(const wxString& name)
+wxFSVolumeBase::wxFSVolumeBase(const wxString& name)
 {
     Create(name);
 } // wxVolume
@@ -452,45 +492,35 @@ wxFSVolume::wxFSVolume(const wxString& name)
 // Function: Create
 // Purpose: Finds, logs in, etc. to the request volume.
 //=============================================================================
-bool wxFSVolume::Create(const wxString& name)
+bool wxFSVolumeBase::Create(const wxString& name)
 {
     // assume fail.
-    m_isOk = FALSE;
+    m_isOk = false;
 
     // supplied.
     m_volName = name;
 
     // Display name.
     SHFILEINFO fi;
-    long rc = SHGetFileInfo(m_volName, 0, &fi, sizeof(fi), SHGFI_DISPLAYNAME);
+    long rc = SHGetFileInfo(m_volName.wx_str(), 0, &fi, sizeof(fi), SHGFI_DISPLAYNAME);
     if (!rc)
     {
-        wxLogError(_("Cannot read typename from '%s'!"), m_volName);
+        wxLogError(_("Cannot read typename from '%s'!"), m_volName.c_str());
         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;
+    return m_isOk = true;
 } // Create
 
 //=============================================================================
 // Function: IsOk
-// Purpose: returns TRUE if the volume is legal.
+// 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
+bool wxFSVolumeBase::IsOk() const
 {
     return m_isOk;
 } // IsOk
@@ -499,7 +529,7 @@ bool wxFSVolume::IsOk() const
 // Function: GetKind
 // Purpose: Return the type of the volume.
 //=============================================================================
-wxFSVolumeKind wxFSVolume::GetKind() const
+wxFSVolumeKind wxFSVolumeBase::GetKind() const
 {
     if (!m_isOk)
         return wxFS_VOL_OTHER;
@@ -516,7 +546,7 @@ wxFSVolumeKind wxFSVolume::GetKind() const
 // Purpose: Return the caches flags for this volume.
 // Notes: - Returns -1 if no flags were cached.
 //=============================================================================
-int wxFSVolume::GetFlags() const
+int wxFSVolumeBase::GetFlags() const
 {
     if (!m_isOk)
         return -1;
@@ -528,46 +558,66 @@ int wxFSVolume::GetFlags() const
     return itr->second.m_flags;
 } // GetFlags
 
-#ifdef wxUSE_GUI
+#endif // wxUSE_BASE
+
+// ============================================================================
+// wxFSVolume
+// ============================================================================
+
+#if wxUSE_GUI
+
+void wxFSVolume::InitIcons()
+{
+    m_icons.Alloc(wxFS_VOL_ICO_MAX);
+    wxIcon null;
+    for (int idx = 0; idx < wxFS_VOL_ICO_MAX; idx++)
+        m_icons.Add(null);
+}
 
 //=============================================================================
 // Function: GetIcon
 // Purpose: return the requested icon.
 //=============================================================================
+
 wxIcon wxFSVolume::GetIcon(wxFSIconType type) const
 {
-    wxCHECK_MSG( type >= 0 && (size_t)type < m_icons.GetCount(),
-                 wxIcon(),                 
-                 _T("invalid icon index") );
+    wxCHECK_MSG( type >= 0 && (size_t)type < m_icons.GetCount(), wxNullIcon,
+                 wxT("wxFSIconType::GetIcon(): invalid icon index") );
 
     // Load on demand.
     if (m_icons[type].IsNull())
     {
-        unsigned flags = 0;
+        UINT flags = SHGFI_ICON;
         switch (type)
         {
         case wxFS_VOL_ICO_SMALL:
-            flags = SHGFI_ICON | SHGFI_SMALLICON;
+            flags |= SHGFI_SMALLICON;
             break;
 
         case wxFS_VOL_ICO_LARGE:
-            flags = SHGFI_ICON | SHGFI_SHELLICONSIZE;
+            flags |= SHGFI_SHELLICONSIZE;
             break;
 
         case wxFS_VOL_ICO_SEL_SMALL:
-            flags = SHGFI_ICON | SHGFI_SMALLICON | SHGFI_OPENICON;
+            flags |= SHGFI_SMALLICON | SHGFI_OPENICON;
             break;
 
         case wxFS_VOL_ICO_SEL_LARGE:
-            flags = SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_OPENICON;
+            flags |= SHGFI_SHELLICONSIZE | SHGFI_OPENICON;
+            break;
+
+        case wxFS_VOL_ICO_MAX:
+            wxFAIL_MSG(wxT("wxFS_VOL_ICO_MAX is not valid icon type"));
             break;
         }
 
         SHFILEINFO fi;
-        long rc = SHGetFileInfo(m_volName, 0, &fi, sizeof(fi), flags);
+        long rc = SHGetFileInfo(m_volName.wx_str(), 0, &fi, sizeof(fi), flags);
         m_icons[type].SetHICON((WXHICON)fi.hIcon);
         if (!rc || !fi.hIcon)
-            wxLogError(_("Cannot load icon from '%s'."), m_volName);
+        {
+            wxLogError(_("Cannot load icon from '%s'."), m_volName.c_str());
+        }
     }
 
     return m_icons[type];
@@ -575,3 +625,4 @@ wxIcon wxFSVolume::GetIcon(wxFSIconType type) const
 
 #endif // wxUSE_GUI
 
+#endif // wxUSE_FSVOLUME