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



背景:

我正在尝试创建一个实用程序,使我们的客户能够轻松地直接在Windows Mobile 6设备(Intermec CK3(上格式化SD卡(实际上是迷你SD卡(。这将比FlashFormat等第三方工具或必须为客户提供读卡器更可取(这需要他们卸下电池,拔出由脆弱的金属外壳固定的迷你SD卡,然后通过文件管理控件运行Windows格式化实用程序(。我们的大多数客户都不太懂技术,所以一个可以自动运行或点击几下的实用程序将是理想的。

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

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

在对这个线程和这个博客进行了一些搜索之后(答案接近底部,由paraGOD回答(,我决定走上一条使用Store Manager API的新道路,它具有FindFirstStore、FindNextStore、OpenStore、DismountStore等功能

我试图在C#中做到这一点,所以我创建了必要的支持结构来表示API中使用的typdfs。这是一个示例:

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函数枚举存储,然后我得到了可怕的,在PInvoke DLL"Coredll.DLL"中找不到入口点"FindFirstStore">错误(在调试器输出中,我还得到SDFormatter.exe中发生了类型为"System.MissingMethodException"的首次机会异常,这是有道理的(。更多的研究表明,在Windows Mobile中,这些功能不会被公开,尽管它们是Coredll的一部分。然而,它们是Windows CE 6的一部分,可以通过平台构建器访问。

以下是我的主要问题:

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

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

感谢

我们有完全相同的要求,但在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);
}

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

最新更新