当有存储卡和蓝牙 ftp 连接时,是否有一种简单的方法可以在 Windows Mobile 设备上找到存储卡的路径?
8 回答
挂载点通常是“\Storage Card”,但可以本地化为其他语言或由 OEM 修改(有些设备使用“\SD Card”或其他挂载点,有些设备支持挂载多个存储介质)。枚举可用卡片的最佳方法是使用 FindFirstFlashCard 和 FindNextFlashCard。
这两个函数都填充了一个 WIN32_FIND_DATA 结构。最重要的字段是 cFileName,它将包含卡安装点的路径(例如“\Storage Card”)。
请注意,这些函数也将枚举设备的内部存储器。如果您只关心外部卷,请忽略 cFileName 为空字符串 ("") 的情况。
使用这些函数需要您#include <projects.h> 并与 note_prj.lib 链接。两者都包含在 WM 2000 及更高版本的 Windows Mobile SDK 中。
请记住,“\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);
}
}
}
}
我发现使用 FindFirstFlashCard/FindNextFlashCard API 比枚举目录和检查临时标志(例如,它将返回蓝牙共享文件夹)更可靠。
以下示例应用程序演示了如何使用它们以及所需的 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);
}
}
有一种纯 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;
}
无法在下面的 TreeUK 和 ctacke 讨论中添加评论:
这不能保证找到存储卡 - 许多设备以相同的方式安装内置闪存,它也会显示在此列表中。– ctacke 5 月 8 日 18:23
这对我来说在 HTC 和 Psion 设备上运行良好。您知道哪些设备无法使用?如果有另一个属性可以打折内置闪存,那将是值得一看的。– TreeUK 5 月 9 日 22:29
为了给出关于摩托罗拉 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 卡。所有都标记为闪存驱动器(它们是),但只有“存储卡”是可移动的。
我在这里发布了用于获取存储卡安装目录的代码。我获得闪存卡路径的部分是从 Sibly 的帖子中复制的,并进行了一些更改。
主要区别在于我搜索所有闪存卡的安装目录,并保留与我从 Windows 注册表读取的默认存储卡名称匹配的目录。
它解决了一个在摩托罗拉的智能设备上有多个闪存卡和只有一个 sd 读卡器的问题,其安装目录的名称可以通过数字后缀从默认值更改(即在英文 WM 系统中:'Storage Card','存储卡 2' 等)。我在一些带有 WM 6.5 英语的摩托罗拉型号(MC75、MC75A、MC90、MC65)上对其进行了测试。
该解决方案应该适用于不同的 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);
}
我结合了上面的一些解决方案,特别是 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();
}
}
在 Windows CE 5(Windows Mobile 6 的基础)上,存储卡作为“Storage Card\”、“Storage Card2\”等安装在根文件系统中。
要确定它是否已挂载,调用 GetFileAttributes(或我相信的远程版本 CeGetFileAttributes)传入完整路径(“\Storage Card\”)。如果它返回 INVALID_FILE_ATTRIBUTES 那么它没有被挂载,否则在返回 true 之前检查以确保它是一个目录。