Domanda

Esiste un modo semplice per trovare il percorso della scheda di archiviazione su un dispositivo mobile Windows quando c'è una scheda di archiviazione e una connessione FTP Bluetooth?

È stato utile?

Soluzione

Tieni presente che "\Storage Card" è orientato all'inglese.Un dispositivo realizzato per una regione diversa potrebbe avere un nome diverso.Il nome del percorso della scheda di memoria sul mio dispositivo varia in base al modo in cui utilizzo il dispositivo.

Qualche tempo fa nei moduli MSDN ho risposto ad alcune domande su come individuare le schede di memoria nel file system e come si ottiene la capacità della scheda di memoria.Ho scritto quanto segue potrebbe essere una risposta a queste domande e ho pensato che sarebbe stato utile condividerlo.Le schede di memoria vengono visualizzate nel file system come directory temporanee.Questo programma esamina gli oggetti nella radice del dispositivo e tutte le cartelle con l'attributo temp vengono considerate una corrispondenza positiva

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace StorageCardInfo
{
    class Program
    {
        const ulong Megabyte = 1048576;
        const ulong Gigabyte = 1073741824;

        [DllImport("CoreDLL")]
        static extern int GetDiskFreeSpaceEx(
        string DirectoryName,
        out ulong lpFreeBytesAvailableToCaller,
        out ulong lpTotalNumberOfBytes,
        out ulong lpTotalNumberOfFreeBytes 
    );

    static void Main(string[] args)
    {
        DirectoryInfo root = new DirectoryInfo("\\");
        DirectoryInfo[] directoryList = root.GetDirectories();
        ulong FreeBytesAvailable;
        ulong TotalCapacity;
        ulong TotalFreeBytes;

        for (int i = 0; i < directoryList.Length; ++i)
        {
            if ((directoryList.Attributes & FileAttributes.Temporary) != 0)
            {
                GetDiskFreeSpaceEx(directoryList.FullName, out FreeBytesAvailable, out TotalCapacity, out TotalFreeBytes);
                Console.Out.WriteLine("Storage card name: {0}", directoryList.FullName);
                Console.Out.WriteLine("Available Bytes : {0}", FreeBytesAvailable);
                Console.Out.WriteLine("Total Capacity : {0}", TotalCapacity);
                Console.Out.WriteLine("Total Free Bytes : {0}", TotalFreeBytes);
            }
        }
    }
}

Altri suggerimenti

Il punto di montaggio è solitamente "\Storage Card" ma può essere localizzato in altre lingue o modificato dagli OEM (alcuni dispositivi utilizzano "\SD Card" o altri punti di montaggio e alcuni dispositivi supportano il montaggio di più supporti di memorizzazione).Il modo migliore per enumerare le schede disponibili è utilizzare FindFirstFlashCard e FindNextFlashCard.

Entrambe le funzioni compilano una struttura WIN32_FIND_DATA.Il campo più importante è cFileName, che conterrà il percorso del punto di montaggio della scheda (ad es."\Scheda di memoria").

Tieni presente che anche la memoria interna del dispositivo verrà enumerata da queste funzioni.Se ti interessano solo i volumi esterni, ignora il caso in cui cFileName è una stringa vuota ("").

L'utilizzo di queste funzioni richiede l'#include <projects.h> e il collegamento con note_prj.lib.Entrambi sono inclusi negli SDK di Windows Mobile per WM 2000 e versioni successive.

Ho scoperto che l'utilizzo delle API FindFirstFlashCard/FindNextFlashCard è più affidabile rispetto all'enumerazione delle directory e al controllo del flag temporaneo (che restituirà, ad esempio, le cartelle condivise Bluetooth).

La seguente applicazione di esempio dimostra come utilizzarli e le istruzioni P/Invoke richieste.

using System;
using System.Runtime.InteropServices;

namespace RemovableStorageTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string removableDirectory = GetRemovableStorageDirectory();
            if (removableDirectory != null)
            {
                Console.WriteLine(removableDirectory);
            }
            else
            {
                Console.WriteLine("No removable drive found");
            }
        }

        public static string GetRemovableStorageDirectory()
        {
            string removableStorageDirectory = null;

            WIN32_FIND_DATA findData = new WIN32_FIND_DATA();
            IntPtr handle = IntPtr.Zero;

            handle = FindFirstFlashCard(ref findData);

            if (handle != INVALID_HANDLE_VALUE)
            {
                do
                {
                    if (!string.IsNullOrEmpty(findData.cFileName))
                    {
                        removableStorageDirectory = findData.cFileName;
                        break;
                    }
                }
                while (FindNextFlashCard(handle, ref findData));
                FindClose(handle);
            }

            return removableStorageDirectory;
        }

        public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);

        // The CharSet must match the CharSet of the corresponding PInvoke signature
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct WIN32_FIND_DATA
        {
            public int dwFileAttributes;
            public FILETIME ftCreationTime;
            public FILETIME ftLastAccessTime;
            public FILETIME ftLastWriteTime;
            public int nFileSizeHigh;
            public int nFileSizeLow;
            public int dwOID;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string cFileName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
            public string cAlternateFileName;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct FILETIME
        {
            public int dwLowDateTime;
            public int dwHighDateTime;
        };

        [DllImport("note_prj", EntryPoint = "FindFirstFlashCard")]
        public extern static IntPtr FindFirstFlashCard(ref WIN32_FIND_DATA findData);

        [DllImport("note_prj", EntryPoint = "FindNextFlashCard")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public extern static bool FindNextFlashCard(IntPtr hFlashCard, ref WIN32_FIND_DATA findData);

        [DllImport("coredll")]
        public static extern bool FindClose(IntPtr hFindFile);
    }
}

Esiste un modo C# puro per eseguire questa operazione senza chiamate native.

Preso da Qui.

//codesnippet:06EE3DE0-D469-44DD-A15F-D8AF629E4E03
public string GetStorageCardFolder()
{
   string storageCardFolder = string.Empty;
   foreach (string directory in Directory.GetDirectories("\\"))
   {
       DirectoryInfo dirInfo = new DirectoryInfo(directory);

       //Storage cards have temporary attributes do a bitwise check.
        //http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=612136&SiteID=1
        if ((dirInfo.Attributes & FileAttributes.Temporary) == FileAttributes.Temporary)
            storageCardFolder = directory;
    }

    return storageCardFolder;
}

Impossibile aggiungere un commento sulla discussione TreeUK e ctacke di seguito:

Questo non è garantito per trovare una scheda di archiviazione: molti dispositivi montano il flash incorporato nello stesso modo, e verrebbe visualizzato anche in questo elenco.- Ctacke 8 maggio alle 18:23
Questo ha funzionato bene per me su dispositivi HTC e Psion.Su quali dispositivi sei consapevole che non funziona?Vale la pena vedere se c'è un altro attributo con cui puoi scontare la costruzione in memoria flash.– TreeUK 9 maggio alle 22:29

Per dare un'idea su un Motorola MC75 (era SymboL), ho usato questo pezzo di codice (nativo):

    WIN32_FIND_DATA cardinfo;
HANDLE  card = FindFirstFlashCard(&cardinfo);
if (card != INVALID_HANDLE_VALUE)
{
    TCHAR existFile[MAX_PATH];

    wprintf(_T("found : %s\n"), cardinfo.cFileName);

    while(FindNextFlashCard(card, &cardinfo))
    {
        wprintf(_T("found : %s\n"), cardinfo.cFileName);
    }
}
FindClose(card);

Uscita di debug:

cardinfo.dwFileAttributes   0x00000110  unsigned long int
cardinfo.cFileName          "Application"   wchar_t[260]

cardinfo.dwFileAttributes   0x00000110  unsigned long int
cardinfo.cFileName          "Cache Disk"    wchar_t[260]

cardinfo.dwFileAttributes   0x00000110  unsigned long int
cardinfo.cFileName          "Storage Card"  wchar_t[260]

L'"Applicazione" e il "Disco cache" sono unità Flash interne.La "Storage Card" è una scheda SD rimovibile.Tutti sono contrassegnati come FlashDrive (e lo sono), ma solo la "Storage Card" è rimovibile.

Ho combinato alcune delle soluzioni di cui sopra, in particolare il codice di qwlice, per trovare le schede SD su una vasta gamma di dispositivi.Questa soluzione trova solo le schede SD (quindi esclude tutte le "schede di memoria" interne di cui dispongono alcuni dispositivi) senza utilizzare chiamate DLL native.

Il codice cerca nella chiave HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\ le chiavi contenenti "SD" poiché il nome varia leggermente su alcuni dispositivi, trova la directory di montaggio predefinita e quindi cerca le directory temporanee che iniziano con questa.Ciò significa che troverà \StorageCard2, \StorageCard3, ecc.

Lo sto usando su una gamma di dispositivi Intermec e Motorola/Symbol e non ho avuto problemi.Ecco il codice qui sotto:

public class StorageCardFinder
{
    public static List<string> GetMountDirs()
    {
        //get default sd card folder name
        string key = @"HKEY_LOCAL_MACHINE\System\StorageManager\Profiles";
        RegistryKey profiles = Registry.LocalMachine.OpenSubKey(@"System\StorageManager\Profiles");
        string sdprofilename = profiles.GetSubKeyNames().FirstOrDefault(k => k.Contains("SD"));
        if (sdprofilename == null)
            return new List<string>();

        key += "\\" + sdprofilename;
        string storageCardBaseName = Registry.GetValue(key, "Folder", "Storage Card") as String;
        if (storageCardBaseName == null)
            return new List<string>();

        //find storage card
        List<string> cardDirectories = GetFlashCardMountDirs();

        List<string> storageCards = new List<string>();
        foreach (string flashCard in GetFlashCardMountDirs())
        {
            string path = flashCard.Trim();
            if (path.StartsWith(storageCardBaseName))
            {
                storageCards.Add("\\" + path);
            }
        }
        return storageCards;
    }

    private static List<string> GetFlashCardMountDirs()
    {
        DirectoryInfo root = new DirectoryInfo("\\");
        return root.GetDirectories().Where(d => (d.Attributes & FileAttributes.Temporary) != 0)
                                    .Select(d => d.Name).ToList();
    }
}

Inserisco qui il codice che utilizzo per ottenere le directory di montaggio delle schede di memoria.La parte in cui ottengo i percorsi delle schede flash è stata copiata dal post di Sibly con alcune modifiche.

La differenza principale sta nel fatto che cerco tra le directory di montaggio di tutte le schede flash e conservo quelle che corrispondono al nome della scheda di memoria predefinita che leggo dal registro di Windows.

Risolve il problema che si ha sui dispositivi smart Motorola in cui sono presenti più schede flash e un solo lettore di schede SD il cui nome della directory di montaggio può cambiare rispetto a quello predefinito tramite il suffisso numerico (es.nei sistemi WM inglesi:"Scheda di memoria", "Scheda di memoria2" e così via).L'ho testato su alcuni modelli di motorola (MC75, MC75A, MC90, MC65) con WM 6.5 inglese.

Questa soluzione dovrebbe funzionare bene con le diverse lingue di Windows Mobile, ma non so se può gestire quelle che cambiano il nome predefinito delle schede di archiviazione.Tutto dipende se il produttore del dispositivo aggiorna il registro di Windows con il file nuovo nome predefinito.

Sarebbe fantastico se potessi testarlo su diversi WM o dispositivi.Il feedback è benvenuto.

   //
   // the storage card is a flash drive mounted as a directory in the root folder 
   // of the smart device
   //
   // on english windows mobile systems the storage card is mounted in the directory "/Storage Card", 
   // if that directory already exists then it's mounted in "/Storage Card2" and so on
   //
   // the regional name of the mount base dir of the storage card can be found in
   // the registry at [HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SDMemory\Folder]
   //  
   // in order to find the path of the storage card we look for the flash drive that starts 
   // with the base name
   //

   public class StorageCard
   {
      private StorageCard()
      {
      }

      public static List<string> GetMountDirs()
      {
         string key = @"HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SDMemory";
         string storageCardBaseName = Registry.GetValue(key, "Folder", "Storage Card") as String;
         List<string> storageCards = new List<string>();
         foreach (string flashCard in GetFlashCardMountDirs())
         {
            string path = flashCard.Trim();
            if (path.StartsWith(storageCardBaseName))
            {
               storageCards.Add(path);
            }
         }
         return storageCards;
      }

      private static List<string> GetFlashCardMountDirs()
      {
         List<string> storages = new List<string>();

         WIN32_FIND_DATA findData = new WIN32_FIND_DATA();
         IntPtr handle = IntPtr.Zero;

         handle = FindFirstFlashCard(ref findData);

         if (handle != INVALID_HANDLE_VALUE)
         {
            do
            {
               if (!string.IsNullOrEmpty(findData.cFileName))
               {
                  storages.Add(findData.cFileName);
                  storages.Add(findData.cAlternateFileName);
               }
            }
            while (FindNextFlashCard(handle, ref findData));
            FindClose(handle);
         }

         return storages;
      }

      private static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);    

      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
      private struct WIN32_FIND_DATA
      {
         public int dwFileAttributes;
         public FILETIME ftCreationTime;
         public FILETIME ftLastAccessTime;
         public FILETIME ftLastWriteTime;
         public int nFileSizeHigh;
         public int nFileSizeLow;
         public int dwOID;
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
         public string cFileName;
         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
         public string cAlternateFileName;
      }

      [StructLayout(LayoutKind.Sequential)]
      private struct FILETIME
      {
         public int dwLowDateTime;
         public int dwHighDateTime;
      };

      [DllImport("note_prj", EntryPoint = "FindFirstFlashCard")]
      private extern static IntPtr FindFirstFlashCard(ref WIN32_FIND_DATA findData);

      [DllImport("note_prj", EntryPoint = "FindNextFlashCard")]
      [return: MarshalAs(UnmanagedType.Bool)]
      private extern static bool FindNextFlashCard(IntPtr hFlashCard, ref WIN32_FIND_DATA findData);

      [DllImport("coredll")]
      private static extern bool FindClose(IntPtr hFindFile);
   }

Su Windows CE 5 (che è la base per Windows Mobile 6) le schede di memoria vengono montate nel file system root come "Storage Card\", "Storage Card2\", ecc.

Per scoprire se è montato chiamare GetFileAttributes (o la versione remota CeGetFileAttributes credo) passando il percorso completo ("\Storage Card\").Se restituisce INVALID_FILE_ATTRIBUTES allora non è montato, altrimenti controlla per assicurarti che sia una directory prima di restituire true.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top