Pregunta

¿Existe una manera fácil de encontrar la ruta de la tarjeta de almacenamiento en un dispositivo de Windows Mobile cuando hay una tarjeta de almacenamiento y una conexión Bluetooth FTP?

¿Fue útil?

Solución

Tenga en cuenta que "\Storage Card" está orientado al inglés.Un dispositivo fabricado para una región diferente puede tener un nombre diferente.El nombre de la ruta de la tarjeta de almacenamiento en mi dispositivo varía según cómo uso el dispositivo.

Hace algún tiempo en los formularios de MSDN respondí algunas preguntas sobre cómo detectar las tarjetas de almacenamiento en el sistema de archivos y cómo se obtiene la capacidad de la tarjeta de almacenamiento.Escribí lo siguiente que podría ser una respuesta a esas preguntas y pensé que sería útil compartirlas.Las tarjetas de almacenamiento aparecen en el sistema de archivos como directorios temporales.Este programa examina los objetos en la raíz del dispositivo y cualquier carpeta que tenga el atributo temporal se considera una coincidencia 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);
            }
        }
    }
}

Otros consejos

El punto de montaje suele ser " arjeta de almacenamiento", pero los OEM pueden traducirlo a otros idiomas o modificarlo (algunos dispositivos usan " arjeta SD" u otros puntos de montaje, y algunos dispositivos admiten el montaje de varios medios de almacenamiento).La mejor manera de enumerar las tarjetas disponibles es utilizar FindFirstFlashCard y FindNextFlashCard.

Ambas funciones completan una estructura WIN32_FIND_DATA.El campo más importante es cFileName, que contendrá la ruta al punto de montaje de la tarjeta (p. ej." arjeta de almacenamiento").

Tenga en cuenta que la memoria interna del dispositivo también estará enumerada por estas funciones.Si solo le interesan los volúmenes externos, ignore el caso en el que cFileName sea una cadena vacía ("").

El uso de estas funciones requiere que #incluya <projects.h> y vincule con note_prj.lib.Ambos están incluidos en los SDK de Windows Mobile para WM 2000 y versiones posteriores.

Descubrí que usar las API FindFirstFlashCard/FindNextFlashCard es más confiable que enumerar directorios y verificar la marca temporal (que devolverá carpetas compartidas de bluetooth, por ejemplo).

La siguiente aplicación de ejemplo demuestra cómo usarlos y las declaraciones P/Invoke requeridas.

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);
    }
}

Hay una forma pura de C# de hacer esto sin llamadas nativas.

Tomado de aquí.

//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;
}

No puedo agregar un comentario sobre la discusión sobre TreeUK y Ctacke a continuación:

Esto no está garantizado para encontrar una tarjeta de almacenamiento: muchos dispositivos montan flash incorporado de la misma manera, y también aparecería en esta lista.- Ctacke 8 de mayo a las 18:23
Esto me ha funcionado bien en los dispositivos HTC y PSion.¿En qué dispositivos sabes que esto no funciona?Vale la pena ver si hay otro atributo con el que puede descartar la compilación con memoria flash.– TreeUK 9 de mayo a las 22:29

Para dar una idea sobre un Motorola MC75 (solía ser SymboL), utilicé este fragmento de código (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);

Salida de depuración:

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]

La "Aplicación" y el "Disco de caché" son unidades flash internas.La "Tarjeta de almacenamiento" es una tarjeta SD extraíble.Todos están marcados como FlashDrive (que lo son), pero sólo la "Tarjeta de almacenamiento" es extraíble.

He combinado varias de las soluciones anteriores, particularmente el código de qwlice, para encontrar tarjetas SD en una variedad de dispositivos.Esta solución solo encuentra tarjetas SD (por lo que excluye todas las "tarjetas de almacenamiento" internas que tienen algunos dispositivos) sin utilizar llamadas dll nativas.

El código busca en la clave HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\ claves que contengan "SD", ya que el nombre varía ligeramente en algunos dispositivos, encuentra el directorio de montaje predeterminado y luego busca directorios temporales que comienzan con este.Esto significa que encontrará \StorageCard2, \StorageCard3, etc.

He estado usando esto en una variedad de dispositivos Intermec y Motorola/Symbol y no he tenido ningún problema.Aquí está el código a continuación:

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();
    }
}

Publico aquí el código que uso para obtener los directorios de montaje de las tarjetas de almacenamiento.La parte donde obtengo las rutas de las tarjetas flash está copiada de la publicación de Sably con algunos cambios.

La principal diferencia es que busco en los directorios de montaje de todas las tarjetas flash y conservo las que coinciden con el nombre de la tarjeta de almacenamiento predeterminada que leí en el registro de Windows.

Resuelve el problema que uno tiene en los dispositivos inteligentes de Motorola donde hay varias tarjetas flash y solo un lector de tarjetas SD cuyo nombre del directorio de montaje puede cambiar del predeterminado por el sufijo numérico (es decir.en ingles sistemas WM:'Tarjeta de almacenamiento', 'Tarjeta de almacenamiento2', etc.).Lo probé en algunos modelos de motorola (MC75, MC75A, MC90, MC65) con WM 6.5 inglés.

Esta solución debería funcionar bien con diferentes idiomas de Windows Mobile, pero no sé si puede lidiar con aquellos que cambian el nombre predeterminado de las tarjetas de almacenamiento.Todo depende de si el fabricante del dispositivo actualiza el registro de Windows con el nuevo nombre predeterminado.

Sería fantástico si pudieras probarlo en diferentes WM o dispositivos.Los comentarios son bienvenidos.

   //
   // 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);
   }

En Windows CE 5 (que es la base de Windows Mobile 6), las tarjetas de almacenamiento se montan en el sistema de archivos raíz como "Tarjeta de almacenamiento\", "Tarjeta de almacenamiento2\", etc.

Para saber si está montado, llame a GetFileAttributes (o creo que a la versión remota CeGetFileAttributes) pasando la ruta completa ("\Storage Card\").Si devuelve INVALID_FILE_ATTRIBUTES entonces no está montado; de lo contrario, verifique que sea un directorio antes de devolver verdadero.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top