如何通过Windows Mobile 6使用Storage Manager API格式化SD卡

时间:2011-08-24 13:49:23

标签: c# windows-mobile compact-framework windows-mobile-6

背景:

我正在尝试创建一个实用程序,允许我们的客户直接在Windows Mobile 6设备(Intermec CK3)上轻松格式化SD卡(实际上是mini-SD)。这将优于诸如FlashFormat之类的第三方工具或者必须向客户提供读卡器(这将要求他们取出电池,拉出由脆弱的金属固定的迷你SD卡)外壳,然后通过文件管理控件运行Windows格式化实用程序)。我们的大多数客户都不是非常精通技术,因此可以自动运行或通过几次点击运行的实用程序是理想的。

到目前为止,我已尝试过以下内容:

  • 看了this个问题。这里的答案似乎不适用于Windows Mobile(例如,没有WMI支持或format.com实用程序)。
  • 尝试使用CreateFileDeviceIoControlCE。这个看起来很有希望,但SD卡似乎永远不会真正格式化。据我所知,这是因为需要首先卸下卡片。
  • 尝试使用CreatFileFormatVolumeEx(以及其他变体FormatVolumeFormateVolumeUI)。结果似乎是相似的,因为我不能格式化卡片,除非它首先被拆除。

在搜索了this thread(由paraGOD接近底部回答)和this blog之后,我决定采用具有此类功能的Store Manager API的新路径如FindFirstStoreFindNextStoreOpenStoreDismountStore等。

我正在尝试在C#中执行此操作,因此我创建了必要的支持结构来表示API中使用的typdef。这是一个样本:

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

然后我创建了一个静态存储管理器类来保存所有存储管理器功能(这些功能应该在用于Windows Mobile 6的coredll中可用......或者我认为是这样):

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

所以我去测试其中的一些功能,例如通过FindFirstStore和FindNextStore函数简单地枚举存储然后我得到了可怕的, 无法找到入口点'FindFirstStore'一个PInvoke DLL'Coredll.dll' 错误(在调试器输出中我也得到 SDFormatter.exe中出现'System.MissingMethodException'类型的第一次机会异常 ,这很有意义)。一些更多的研究暗示,在Windows Mobile中,即使它们是Coredll的一部分,也不会暴露这些功能。但它们是Windows CE 6的一部分,可以通过平台构建器访问。

以下是我的主要问题:

  • 我可以通过Windows Mobile 6中的C#访问Storage Manager API吗?
  • 如果没有,我可以通过托管C ++编写一个实用程序(我不太了解,但如果有必要,我会偶然发现它),但不必使用平台构建器(它不是免费的)?
  • 如果只能通过平台构建器,这是否意味着我要么自己构建自己的SDK还是要让Intermec为我公开这些功能?

如果有人有建议,我也愿意完全采用另一种方式(最好通过C#)。我想也许让客户将设备安装在底座上并运行桌面实用程序。不确定这是否可行并且它不能依赖ActiveSync(我们不想再支持另一个工具,所以我们通过连接到底座的网络适配器向SD卡发送数据,使用套接字在我们之间进行通信自定义服务器程序和我们的移动应用程序。)

由于

2 个答案:

答案 0 :(得分:2)

我们有完全相同的要求,但在Windows CE上。我们的解决方案是创建一个小型C ++应用程序,然后从C#代码中调用它。这是C ++应用程序中最重要的部分:

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

答案 1 :(得分:0)

FindFirstStore可在Windows Mobile 5.0及更高版本的公共API设备上使用,因此您不需要像平台构建器那样的任何想法。

我想我读过某个地方,FindFirstStore只被转移到CE6中的coredll.dll(我不记得我在哪里看到了)。因此,您的Windows Mobile 6设备可能会从其他地方导出它。 (可能是storeapi.dll吗?)

尝试使用此代码创建C ++项目,看看它是否适合您:

#pragma comment( lib, "storeapi.lib" )

int _tmain( int /*argc*/, _TCHAR* /*argv*/[] )
{
    STOREINFO si = { 0 };
    si.cbSize = sizeof( STOREINFO );

    HANDLE ffs = ::FindFirstStore( &si );
    if( INVALID_HANDLE_VALUE != ffs )
    {
        ::FindCloseStore( ffs );
    }
    return 0;
}