背景:
我正在尝试创建一个实用工具,让我们的客户可以直接在Windows Mobile 6设备(Intermec CK3)上轻松格式化SD卡(实际上是mini-SD)。这比使用第三方工具如FlashFormat或为客户提供读卡器更可取(这将需要他们拆下电池,拉出由脆弱金属外壳固定的mini-SD卡,然后通过文件管理控制运行Windows格式化实用程序)。我们大部分的客户并不是很精通技术,因此一个可以自动运行或只需几次点击即可运行的工具是理想的。
我已经尝试了以下方式:
- 查看这个问题。这里的答案似乎不适用于Windows Mobile(例如没有WMI支持或format.com实用程序)。
- 尝试使用CreateFile和DeviceIoControlCE。这个方法看起来很有前途,但是SD卡似乎永远无法真正格式化。据我所知,这是因为首先需要卸载该卡。
- 尝试使用CreatFile和FormatVolumeEx(以及其他变体,如FormatVolume和FormateVolumeUI)。结果似乎类似,除非首先卸载卡片,否则无法格式化该卡。
在进行了一些搜索并遇到此主题(由paraGOD在底部回答),以及这篇博客之后,我决定采用使用存储管理器 API的新路径,该API具有FindFirstStore,FindNextStore,OpenStore,DismountStore等函数。
我正在尝试使用C#进行此操作,因此我创建了必要的支持结构来表示API中使用的typedefs。这是一个示例:
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的一部分,并可以通过平台构建器访问。
因此,这里是我主要的问题:
- 我是否可以以某种方式通过C#访问Windows Mobile 6中的Storage Manager API?
- 如果不行,是否可以通过托管的C ++编写实用程序(我不太懂,但如果必要,我会摸索过去),但不必使用平台构建器(它不免费)?
- 如果只能通过平台构建器实现,那么这是否意味着我要么被困在构建自己的SDK中,要么必须要求Intermec为我公开功能?
如果有人有建议,我也很愿意从完全另一个角度解决这个问题(最好是通过C#)。我想也许让客户将设备安装在底座上并运行桌面实用程序是一个好方法。不确定这是否可行,并且它不能依赖于ActiveSync(我们不想支持另一个工具,因此我们通过连接到插座的网络适配器通过套接字在自定义服务器程序和我们的移动应用程序之间进行通信来发送数据到和从SD卡)。
谢谢