Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you format an SD card using the Storage Manager API via Windows Mobile 6

Background:

I'm trying to create a utility that will allow our customers to easily format an SD card (actually mini-SD) directly on a Windows Mobile 6 device (Intermec CK3). This would be preferred over a thrid party tool such as FlashFormat or having to provide card readers to the customers (which would require them to remove the battery, pull out the mini-SD card which is held in by a flimsy metal housing, and then run the Windows formatting utility via the file management control). Most of our customers are not very tech-savvy, so a utility that can be run automatically or via a couple clicks would be ideal.

I've tried the following so far:

  • Looked at this question. The answers in here do not seem to work for Windows Mobile (e.g. no WMI support or format.com utility).
  • Tried using CreateFile and DeviceIoControlCE. This one seemed promising, but the SD card would never seem to actually format. From what I could tell, it was because the card needed to be dismounted first.
  • Tried using CreatFile and FormatVolumeEx (along with the other variants, FormatVolume and FormateVolumeUI). The result seemed to be similar in that I could not format the card unless it was first dismounted.

After doing some searching an running into this thread (answer near bottom by paraGOD) and this blog, I decided to go down a new path of using the Store Manager API, which has such functions as FindFirstStore, FindNextStore, OpenStore, DismountStore and so on.

I'm trying to do this in C#, so I created the necessary supporting structs to represent the typdefs used in the API. Here is a sample one:

using System.Runtime.InteropServices;

// Try to match the struct typedef exactly (all caps, exact type names).
using DWORD = System.UInt32;
using TCHAR = System.String;

namespace SDFormatter
{
    // http://msdn.microsoft.com/en-us/library/ee490035(v=WinEmbedded.60).aspx
    // STORAGEDEVICEINFO (Storage Manager)

    [StructLayout(LayoutKind.Sequential)]
    public struct StorageDeviceInfo
    {
        public DWORD cbSize;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
        public TCHAR szProfile;
        public DWORD dwDeviceClass;
        public DWORD dwDeviceType;
        public DWORD dwDeviceFlags;
    }
}

Then I created a static storage manager class to hold all of the storage manager functions (which are supposed to be available in coredll for windows mobile 6... or so I thought):

using System.Runtime.InteropServices;

// Try to match the Coredll functions exactly (all caps, exact type names, etc.).
using BOOL = System.Boolean;
using BYTE = System.Byte;
using DWORD = System.UInt32;
using HANDLE = System.IntPtr;
using LPCE_VOLUME_INFO = System.IntPtr;
using LPCSTR = System.String;
using LPCTSTR = System.String;
using LPCWSTR = System.String;
using PPARTINFO = System.IntPtr;
using PSTOREINFO = System.IntPtr;
using SECTORNUM = System.UInt64;

// ReSharper disable InconsistentNaming
namespace SDFormatter
{
    // http://msdn.microsoft.com/en-us/library/ee490420(v=WinEmbedded.60).aspx

    public static class StorageManager
    {
        [DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CeGetVolumeInfo(LPCWSTR pszRootPath, CE_VOLUME_INFO_LEVEL InfoLevel,
                                                  LPCE_VOLUME_INFO lpVolumeInfo);

        [DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CreatePartition(HANDLE hStore, LPCTSTR szPartitionName, SECTORNUM snNumSectors);

        [DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CreatePartitionEx(HANDLE hStore, LPCTSTR szPartitionName, BYTE bPartType,
                                                    SECTORNUM snNumSectors);

        [DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool DeletePartition(HANDLE hStore, LPCTSTR szPartitionName);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool DismountPartition(HANDLE hPartition);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool DismountStore(HANDLE hStore);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool FindClosePartition(HANDLE hSearch);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool FindCloseStore(HANDLE hSearch);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern HANDLE FindFirstPartition(HANDLE hStore, PPARTINFO pPartInfo);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern HANDLE FindFirstStore(PSTOREINFO pStoreInfo);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool FindNextPartition(HANDLE hSearch, PPARTINFO pPartInfo);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool FindNextStore(HANDLE hSearch, PSTOREINFO pStoreInfo);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool FormatPartition(HANDLE hPartition);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool FormatPartitionEx(HANDLE hPartition, BYTE bPartType, BOOL bAuto);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool FormatStore(HANDLE hStore);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool GetPartitionInfo(HANDLE hPartition, PPARTINFO pPartInfo);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool GetStoreInfo(HANDLE hStore, PSTOREINFO pStoreInfo);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool MountPartition(HANDLE hPartition);

        [DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern HANDLE OpenPartition(HANDLE hStore, LPCTSTR szPartitionName);

        [DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern HANDLE OpenStore(LPCSTR szDeviceName);

        [DllImport("Coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool RenamePartition(HANDLE hPartition, LPCTSTR szNewName);

        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool SetPartitionAttributes(HANDLE hPartition, DWORD dwAttrs);

        // http://msdn.microsoft.com/en-us/library/ee490442(v=winembedded.60).aspx
        [DllImport("Coredll.dll", SetLastError = true)]
        public static extern bool CloseHandle(HANDLE hObject);
    }

    public enum CE_VOLUME_INFO_LEVEL
    {
        CeVolumeInfoLevelStandard = 0
    }
}
// ReSharper restore InconsistentNaming

So I went to test some of these functions, such as simply enumerating through the stores via the FindFirstStore and FindNextStore functions and then I get the dreaded, Can't find an Entry Point 'FindFirstStore' in a PInvoke DLL 'Coredll.dll' error (in the debugger output I also get A first chance exception of type 'System.MissingMethodException' occurred in SDFormatter.exe, which makes sense). Some more research hinted that in Windows Mobile, these functions aren't exposed, even though they are part of Coredll. They are however part of Windows CE 6 and can be accessed via platform builder.

So here are the main questions I have:

  • Can I access the Storage Manager API via C# in Windows Mobile 6 some how?
  • If not, can I write a utility via managed C++ (I'm don't know much, but I'll stumble through it if necessary), but without having to use platform builder (it's not free)?
  • If it is only possible via platform builder, does that mean I'm either stuck building my own SDK or will have to ask Intermec to expose the functionality for me?

I'm also open to doing this another way entirely (preferrably via C#) if anyone has suggestions. I was thinking maybe having the customer mount the device in the cradle and running a desktop utility. Not sure if this is possible and it can't rely on ActiveSync (we don't want to support yet another tool, so we send data to and from the SD card via a network adapter connected to the cradle using sockets to talk between our custom server program and our mobile application).

Thanks

like image 500
Jason Down Avatar asked Aug 24 '11 13:08

Jason Down


1 Answers

We had the exact same requirement, but on Windows CE. Our solution was to create a small C++ application, which is then called from the C# code. Here is the most important part of the C++ application:

#include <windows.h>
#include <Storemgr.h>

int _tmain( int /*argc*/, _TCHAR* /*argv*/[] )
{
    WCHAR szDisk[] = L"DSK0";

    hDsk = OpenStore(szDisk);
    if(hDsk == INVALID_HANDLE_VALUE) 
      // ERROR  : Opening Store 

    if (!GetStoreInfo(hDsk, &si))
      // ERROR  : Getting Store Info 

    if(!DismountStore(hDsk)) 
      // ERROR  : Dismounting Store

    if(!FormatStore(hDsk)) 
      // ERROR  : Formatting Store 

    CloseHandle(hDsk);
}
like image 87
ollifant Avatar answered Oct 22 '22 09:10

ollifant