16

背景:

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

到目前为止,我已经尝试了以下方法:

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

在搜索了这个线程(paraGOD 在底部附近回答)和这个博客之后,我决定走一条使用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;
    }
}

然后我创建了一个静态存储管理器类来保存所有存储管理器功能(应该在 coredll for windows mobile 6 中可用......或者我认为):

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 卡发送数据和从 SD 卡发送数据,使用套接字在我们的自定义服务器程序和我们的移动应用程序)。

谢谢

4

2 回答 2

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);
}
于 2012-02-04T10:55:37.330 回答
0

FindFirstStore在公共 API 中的 Windows Mobile 5.0 和更高版本的设备上可用,因此您不需要像平台构建器这样的花哨的东西。

我想我在某处读到 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;
}
于 2011-08-29T19:20:26.630 回答