2008-09-02 17 views

Respuesta

5

Ten en cuenta que "\ Storage Card" está orientado al inglés. Un dispositivo hecho 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 con la forma en que estoy usando 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 podría ser una respuesta a esas preguntas y pensé que sería útil compartir. 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 las carpetas que tienen el atributo temporal se considera un resultado positivo

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

Las carpetas que no sean de almacenamiento pueden aparecer como Temporales, por lo que no es muy confiable. Si realmente desea saber, entonces P/Invocar FindFirstFlashCard (http://msdn.microsoft.com/en-us/library/ms840697.aspx) es confiable. Así que está buscando el evento de montaje del dispositivo desde el administrador del dispositivo. – ctacke

+0

El código utilizado anteriormente es lo que terminé usando en mi programa. Encontré algunos recursos en channel9 sobre tarjetas de almacenamiento y eso es lo que usaron también. –

+0

FindFirstFlashCard tampoco es confiable. Tengo un dispositivo (Handheld Nautiz X5) que tiene otra carpeta en la raíz llamada "ProgramStore". Si utilizo FindFirstFlashCard, obtengo el ProgramStore en lugar de la "Tarjeta de almacenamiento". – Ted

1

en Windows CE 5 (que es la base para Windows Mobile 6) tarjetas montará en el sistema de archivos raíz que "Tarjeta de almacenamiento \" almacenamiento "Storage Card2 \", etc.

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

+0

No es seguro codificar la ruta \ Storage Card. Vea mi respuesta para ver cómo obtener la (s) ruta (s) de cualquier (s) tarjeta (s) montada (s). –

10

El punto de montaje suele ser "\ Storage Card" pero puede ser traducido a otros idiomas o modificado por OEM (algunos dispositivos usan "\ SD Card" 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 usar 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 (por ejemplo, "\ Storage Card").

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

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

+0

Buena respuesta, lo mejor para la pregunta en mi humilde opinión. –

4

que he encontrado usando la FindFirstFlashCard/FindNextFlashCard APIs para ser más fiable que la enumeración de directorios y verificando el indicador temporal (que devolverá las carpetas compartidas de bluetooth, por ejemplo).

La siguiente aplicación de ejemplo muestra cómo usarlas 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); 
    } 
} 
+0

FindFirstFlashCard tampoco es confiable. Tengo un dispositivo (Handheld Nautiz X5) que tiene otra carpeta en la raíz llamada "ProgramStore". Si utilizo FindFirstFlashCard, obtengo el ProgramStore en lugar de la "Tarjeta de almacenamiento". – Ted

2

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

Tomado de here.

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

No se garantiza que encuentre una tarjeta de almacenamiento; muchos dispositivos montan el flash incorporado de la misma manera, y también aparecería en esta lista. – ctacke

+0

Esto me ha funcionado en dispositivos HTC y Psion. ¿Qué dispositivos sabes que esto no funciona? Merece la pena ver si hay otro atributo con el que puede descontar la construcción en la memoria flash. –

3

No se puede agregar un comentario en la TreeUK y discusión ctacke a continuación:

Esto no está garantizado para encontrar una tarjeta de almacenamiento - montan muchos dispositivos flash incorporado en la misma teh manera, y aparecería en esta lista también. - ctacke 8 de mayo a las 18:23
Esto tiene funcionó bien para mí en dispositivos HTC y Psion . ¿Qué dispositivos conoce esto no funciona? Valdría ver si hay otro atributo puede descontar la construcción en memoria flash con. - TreeUK 9 de mayo a 22:29

Para dar una idea sobre un Motorola MC75 (solía ser símbolo), he utilizado esta pieza (de nativo) código:

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

La 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 son), pero solo la "Tarjeta de almacenamiento" es extraíble.

3

Publiqué aquí el código que utilizo para obtener los directorios de montaje de las tarjetas de almacenamiento. La parte donde obtengo las rutas de las tarjetas flash se copia de la publicación de Sibly con algunos cambios.

La principal diferencia es que busco a través de los directorios de montaje de todas las tarjetas flash y guardo las que coinciden con el nombre predeterminado de la tarjeta de almacenamiento 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 tarjeta sd cuyo nombre de directorio puede cambiar de forma predeterminada por el sufijo numérico (es decir, en inglés WM systems: 'Almacenamiento Tarjeta ',' Tarjeta de almacenamiento2 ', etc.). Lo probé en algunos modelos de motorola (MC75, MC75A, MC90, MC65) con WM 6.5 en inglés.

Esta solución debería funcionar bien con los diferentes idiomas de Windows Mobile, pero no sé si puede tratar 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 genial si puedes probarlo en diferentes WM o dispositivos. 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); 
    } 
+0

Probé este código para ver si podía averiguar cómo debería llamar a mis "unidades flash internas", supongo que se llaman, IOW cómo apuntar a un archivo específico en mi dispositivo de mano, pero tengo "Sistema .DllNotFoundException no se ha manejado HResult = -2146233052 Mensaje = Imposible cargar DLL 'note_prj': No se pudo encontrar el módulo especificado. " note_prj? –

3

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

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

He estado usando esto en una gama 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(); 
    } 
} 
Cuestiones relacionadas