Есть ли простой способ найти путь к карте памяти на устройстве Windows Mobile? когда есть карта памяти и подключение по bluetooth ftp?





В Windows CE 5 (которая является базой для Windows Mobile 6) карты памяти монтируются в корневой файловой системе как «Storage Card \», «Storage Card2 \» и т. д.
Чтобы узнать, смонтирован ли он, вызовите GetFileAttributes (или, как мне кажется, удаленную версию CeGetFileAttributes), передав полный путь ("\ Storage Card \"). Если он возвращает INVALID_FILE_ATTRIBUTES, значит, он не смонтирован, в противном случае убедитесь, что это каталог, прежде чем возвращать истину.
Точкой монтирования обычно является «\ Storage Card», но она может быть локализована на другие языки или изменена OEM-производителями (некоторые устройства используют «\ SD Card» или другие точки подключения, а некоторые устройства поддерживают подключение нескольких носителей). Лучший способ перечислить доступные карты - использовать FindFirstFlashCard и FindNextFlashCard.
Обе функции заполняют структуру WIN32_FIND_DATA. Наиболее важным полем является cFileName, которое будет содержать путь к точке монтирования карты (например, «\ Storage Card»).
Обратите внимание, что внутренняя память устройства также будет пронумерована этими функциями. Если вас интересуют только внешние тома, не обращайте внимания на случай, когда cFileName представляет собой пустую строку ("").
Для использования этих функций вам потребуется #include <projects.h> и ссылка на note_prj.lib. Оба включены в SDK Windows Mobile для WM 2000 и более поздних версий.
Хороший ответ, лучший на вопрос ИМХО.
Имейте в виду, что "\ Storage Card" ориентирована на английский язык. Устройство, предназначенное для другого региона, может иметь другое имя. Имя пути к карте памяти на моем устройстве зависит от того, как я его использую.
Некоторое время назад в формах MSDN я ответил на несколько вопросов о том, как определять карты памяти в файловой системе и как определить емкость карты памяти. Я написал следующее, что могло бы стать ответом на эти вопросы, и подумал, что было бы полезно поделиться им. Карты памяти отображаются в файловой системе как временные каталоги. Эта программа проверяет объекты в корне устройства, и любые папки с атрибутом temp считаются положительным совпадением.
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);
}
}
}
}
Папки, отличные от карт памяти, могут отображаться как временные, так что это не очень надежно. Если вы действительно хотите знать, то P / Вызов FindFirstFlashCard (msdn.microsoft.com/en-us/library/ms840697.aspx) надежен. Итак, ищем событие монтирования устройства из диспетчера устройств.
Приведенный выше код - это то, что я в итоге использовал в своей программе. Я нашел на канале 9 ресурсы о картах памяти, которые они тоже использовали.
FindFirstFlashCard тоже ненадежна. У меня есть устройство (Handheld Nautiz X5), в корне которого есть еще одна папка под названием «ProgramStore». Если я использую FindFirstFlashCard, я получаю ProgramStore вместо «Storage Card».
Я обнаружил, что использование API FindFirstFlashCard / FindNextFlashCard более надежно, чем перечисление каталогов и проверка временного флага (который, например, вернет общие папки bluetooth).
В следующем примере приложения показано, как их использовать и необходимые операторы P / Invoke.
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);
}
}
FindFirstFlashCard тоже ненадежна. У меня есть устройство (Handheld Nautiz X5), в корне которого есть еще одна папка под названием «ProgramStore». Если я использую FindFirstFlashCard, я получаю ProgramStore вместо «Storage Card».
Есть чистый C# способ сделать это без собственных вызовов.
Взято из здесь.
//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;
}
Не гарантируется, что вы найдете карту памяти - многие устройства устанавливают встроенную флеш-память таким же образом, и она также будет отображаться в этом списке.
У меня это хорошо сработало на устройствах HTC и Psion. На каких устройствах вы знаете, что это не работает? Стоит посмотреть, есть ли еще один атрибут, с помощью которого можно сбрасывать со счетов сборку флеш-памяти.
Не могу добавить комментарий к обсуждению TreeUK и ctacke ниже:
This isn't guaranteed to find a Storage Card - many devices mount built-in flash in teh same way, and it would show up in this list as well. – ctacke May 8 at 18:23
This has worked well for me on HTC and Psion devices. What devices are you aware this doesn't work on? Would be worth seeing if there's another attribute you can discount the build in flash memory with. – TreeUK May 9 at 22:29
Чтобы дать представление о Motorola MC75 (раньше назывался SymboL), я использовал этот фрагмент (собственного) кода:
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);
Вывод отладки:
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]
«Приложение» и «Кэш-диск» - это внутренние флэш-накопители. «Карта памяти» - съемная SD-карта. Все они помечены как флэш-накопители (каковыми они и являются), но только «карта памяти» является съемной.
Я размещаю здесь код, который использую для получения директорий монтирования карт памяти. Часть, где я получаю пути к флеш-картам, скопирована из сообщения Сибли с небольшими изменениями.
Основное отличие состоит в том, что я просматриваю каталоги монтирования всех флеш-карт и сохраняю те, которые соответствуют имени карты памяти по умолчанию, которое я прочитал из реестра Windows.
Это решает проблему, которая есть на смарт-устройствах Motorola, где есть несколько флэш-карт и только одно устройство чтения SD-карт, имя каталога для монтирования которого может измениться по сравнению с именем по умолчанию с помощью числового суффикса (например, в английских системах WM: 'Storage Card', ' Storage Card2 'и так далее). Я тестировал его на некоторых моделях Motorola (MC75, MC75A, MC90, MC65) с английской версией WM 6.5.
Это решение должно хорошо работать с разными языками Windows Mobile, но я не знаю, сможет ли оно справиться с теми, которые меняют имя по умолчанию для карт памяти. Все зависит от того, обновляет ли производитель устройства реестр Windows с именем по умолчанию новый.
Было бы здорово, если бы вы могли протестировать его на разных WM или устройствах. Обратная связь приветствуется.
//
// 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);
}
Я попробовал этот код, чтобы узнать, могу ли я узнать, что я должен «называть» своими «внутренними флэш-накопителями», я думаю, они называются, IOW, как указать на конкретный файл на моем портативном устройстве, но я получил «Система. Необработанное исключение DllNotFoundException HResult = -2146233052 Сообщение = Невозможно загрузить DLL 'note_prj': указанный модуль не найден. " note_prj?
Я объединил ряд вышеперечисленных решений, в частности код qwlice, чтобы найти SD-карты на различных устройствах. Это решение находит только SD-карты (поэтому исключает все внутренние «карты памяти», которые есть на некоторых устройствах) без использования собственных вызовов dll.
Код ищет ключ HKEY_LOCAL_MACHINE \ System \ StorageManager \ Profiles \ в поисках ключей, содержащих «SD», так как имя немного меняется на некоторых устройствах, находит каталог монтирования по умолчанию, а затем ищет временные каталоги, которые начинаются с этого. Это означает, что он найдет \ StorageCard2, \ StorageCard3 и т. д.
Я использовал это на ряде устройств Intermec и Motorola / Symbol, и у меня не было никаких проблем. Вот код ниже:
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();
}
}
Жестко указывать путь \ Storage Card небезопасно. См. Мой ответ, чтобы узнать, как получить путь (пути) к любой установленной карте (ам).