如何通过 Windows Mobile 6 使用存储管理器 API 格式化 SD 卡
背景:
我正在尝试创建一个实用程序,允许我们的客户直接在 Windows Mobile 6 设备 (Intermec CK3) 上轻松格式化 SD 卡(实际上是迷你 SD)。这比第三方工具(例如 FlashFormat 更受青睐)或者必须向客户提供读卡器(这需要他们取出电池,拔出由脆弱的金属外壳固定的迷你 SD 卡,然后通过文件管理控制)。我们的大多数客户都不太懂技术,因此可以自动运行或通过几次点击运行的实用程序将是理想的选择。
到目前为止,我已经尝试过以下操作:
- 查看 这个问题。这里的答案似乎不适用于Windows Mobile(例如,没有WMI 支持或format.com 实用程序)。
- 尝试使用 CreateFile 和 DeviceIoControlCE。这看起来很有希望,但 SD 卡似乎永远不会真正格式化。据我所知,这是因为需要先将卡拆下来。
- 尝试使用 CreatFile 和 FormatVolumeEx(以及其他变体,FormatVolume 和 FormateVolumeUI)。结果似乎相似,除非先将卡卸下,否则我无法格式化该卡。
进行一些搜索后,遇到 这个帖子(paraGOD在底部附近回答)和这个博客,我决定走一条使用 商店管理器API,具有以下功能:查找第一家商店,FindNextStore,OpenStore,DismountStore 等等。
我尝试在 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 函数简单地枚举存储,然后我得到可怕的,Can't find an Entry Point 'FindFirstStore' in a PInvoke DLL 'Coredll.dll' 错误(在调试器输出中,我还得到A first opportunity exception of type 'System.MissingMethodException'发生在 SDFormatter.exe,这是有道理的)。更多研究表明,在 Windows Mobile 中,这些函数并未公开,即使它们是 Coredll 的一部分。然而,它们是 Windows CE 6 的一部分,可以通过平台构建器进行访问。
以下是我的主要问题:
- 我可以在 Windows Mobile 6 中通过 C# 访问 Storage Manager API吗?
- 如果没有,我可以通过托管 C++ 编写一个实用程序(我知道的不多,但如果需要的话我会偶然发现它),但不必使用平台构建器(它不是免费的)?
- 如果只能通过平台构建器实现,这是否意味着我要么只能构建自己的 SDK,要么必须要求 Intermec 为我公开该功能?
如果有人有建议,我也愿意完全采用另一种方式(最好通过 C#)。我在想也许让客户将设备安装在支架上并运行桌面实用程序。不确定这是否可行,并且不能依赖 ActiveSync(我们不想支持另一种工具,因此我们通过连接到支架的网络适配器向 SD 卡发送数据或从 SD 卡发送数据,使用套接字在我们的设备之间进行通信自定义服务器程序和我们的移动应用程序)。
谢谢
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我们有完全相同的要求,但是是在 Windows CE 上。我们的解决方案是创建一个小型 C++ 应用程序,然后从 C# 代码中调用该应用程序。这是 C++ 应用程序中最重要的部分:
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:
FindFirstStore 可在 Windows Mobile 5.0 及更高版本设备上的公共 API 中使用,所以你不需要任何像平台构建器这样的奇特东西。
我想我在某处读到,FindFirstStore 在 CE6 中仅被移至 coredll.dll(我不记得在哪里看到过)。因此,您的 Windows Mobile 6 设备可能会从其他地方导出它。 (可能是 storeapi.dll?)
尝试使用以下代码创建一个 C++ 项目,看看它是否适合您:
FindFirstStore is available on Windows Mobile 5.0 and later devices in the public API, so you shouldn't need anything fancy like platform builder.
I think I read somewhere that FindFirstStore was only moved to coredll.dll in CE6 (I can't remember where I saw that). So, your Windows Mobile 6 device will probably have it exported from somewhere else. (possibly storeapi.dll?)
Try creating a C++ project with this code and see if it works for you: