Is there an easy way to find the storage card's path on a Windows Mobile device when there is a storage card and a bluetooth ftp connection?
On Windows CE 5 (which is the base for Windows Mobile 6) the storage cards get mounted at the root file system as "Storage Card\", "Storage Card2\", etc.
To find out if it's mounted call GetFileAttributes (or the remote version CeGetFileAttributes I believe) passing in the full path ("\Storage Card\"). If it returns INVALID_FILE_ATTRIBUTES then it's not mounted, otherwise check to make sure it's a directory before returning true.
The mount point is usually "\Storage Card" but can be localized into other languages or modified by OEMs (some devices use "\SD Card" or other mount points, and some devices support mounting multiple storage media). The best way to enumerate the available cards is to use FindFirstFlashCard and FindNextFlashCard.
Both functions fill in a WIN32_FIND_DATA structure. The most important field is cFileName, which will contain the path to the card's mount point (e.g. "\Storage Card").
Note that the device's internal memory will also be enumerated by these functions. If you only care about external volumes, ignore the case where cFileName is an empty string ("").
Using these functions require you to #include <projects.h> and link with note_prj.lib. Both are included in the Windows Mobile SDKs for WM 2000 and later.
Keep in mind that "\Storage Card" is english oriented. A device made for a different region may have a different name. The name of the storage card path on my device varies with how I am using the device.
Some time ago in the MSDN forms I responded to a few questions on how to detect the storage cards in the file system and how does one get the storage card's capacity. I wrote the following could are a response to those questions and thought it would be helpful to share. Storage cards show up in the file system as temporary directories. This program examines the objects in the root of the device and any folders that have temp attribute are considered to be a positive match
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);
}
}
}
}
I've found using the FindFirstFlashCard/FindNextFlashCard APIs to be more reliable than enumerating directories and checking the temporary flag (which will return bluetooth shared folders for example).
The following sample application demonstrates how to use them and the required P/Invoke statements.
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);
}
}
There's a pure C# way to do this without native calls.
Taken from 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;
}
Hello All,
Can't add a comment on the TreeUK and ctacke discusion below :
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
To give a idea on a Motorola MC75 (used to be SymboL), i used this piece (of native) code :
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);
Debug output :
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]
The "Application" and "Cache disk" are internal Flash drives. The "Storage Card" a removable SD Card. All are marked as a FlashDrive (which they are), but only "Storage Card" is removable.