Как отформатировать SD-карту с помощью API диспетчера хранилища с помощью Windows Mobile 6

Фон:

Я пытаюсь создать утилиту, которая позволит нашим клиентам легко форматировать SD-карту (фактически мини-SD) непосредственно на устройстве Windows Mobile 6 (Intermec CK3). Это было бы предпочтительнее, чем при использовании стороннего инструмента, такого как FlashFormat или для предоставления читателям карт читателям (что потребовало бы их для извлечения батареи, вытащите мини-SD-карту, которая удерживается в непрозрачном металлическом корпусе, а затем запустите утилиту форматирования Windows с помощью элемента управления файлами). Большинство наших клиентов не очень хорошо разбираются в технологиях, поэтому утилита, которая может запускаться автоматически или через несколько кликов, была бы идеальной.

Я пробовал следующее:

  • Посмотрел на этот вопрос. Ответы здесь не работают для Windows Mobile (например, нет поддержки WMI или утилиты format.com).
  • Пробовал использовать CreateFile и DeviceIoControlCE. Это казалось многообещающим, но SD-карта никогда, казалось бы, не форматировала бы. Из того, что я мог сказать, это было из-за того, что сначала нужно было разобрать карту.
  • Пробовал использовать CreatFile и FormatVolumeEx (вдоль с другими вариантами, FormatVolume и FormateVolumeUI). Результат, похоже, был похож на то, что я не мог отформатировать карту, если она не была впервые снята.

После выполнения поиска в этот поток (ответьте внизу снизу на paraGOD) и этот блог, я решил перейти по новому пути использования Менеджера хранилища API, который имеет такие как FindFirstStore, FindNextStore, OpenStore, DismountStore и т.д.

Я пытаюсь сделать это на С#, поэтому я создал необходимые поддерживающие структуры для представления typdefs, используемых в API. Вот пример:

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 для 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, а затем я получаю страшный, Не удается найти точку входа FindFirstStore в DLL PInvoke Ошибка "Coredll.dll" (на выходе отладчика я также получаю . Первое случайное исключение типа "System.MissingMethodException" произошло в SDFormatter.exe, что имеет смысл). Еще несколько исследований намекнули, что в Windows Mobile эти функции не отображаются, хотя они и являются частью Coredll. Однако они являются частью Windows CE 6 и могут быть доступны через конструктор платформ.

Итак, вот основные вопросы, которые у меня есть:

  • Можно ли получить доступ к API диспетчера хранилища через С# в Windows Mobile 6?
  • Если нет, могу ли я написать утилиту через управляемый С++ (я не знаю многого, но я буду спотыкаться, если это необходимо), но без использования конструктора платформы (это не бесплатно)?
  • Если это возможно только через конструктор платформ, значит ли это, что я либо застреваю, строя свой собственный SDK, либо мне придется спросить Intermec о том, чтобы предоставить мне функциональность?

Я также открыт для этого совершенно другим способом (желательно через С#), если у кого есть предложения. Я подумал, что, возможно, клиент установит устройство в подставку и запустит настольную утилиту. Не уверен, что это возможно, и он не может полагаться на ActiveSync (мы не хотим поддерживать еще один инструмент, поэтому мы отправляем данные на SD-карту и с нее через сетевой адаптер, подключенный к подставке, используя сокеты для разговора между нашими пользовательская серверная программа и наше мобильное приложение).

Спасибо

Ответы

Ответ 1

У нас было то же самое требование, но в Windows CE. Наше решение состояло в том, чтобы создать небольшое С++-приложение, которое затем вызывается из кода С#. Вот самая важная часть приложения С++:

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

Ответ 2

FindFirstStore доступен на устройствах Windows Mobile 5.0 и более поздних версиях в общедоступном API, поэтому вам не нужно ничего такого, как конструктор платформ.

Я думаю, что я где-то читал, что FindFirstStore был перемещен только в coredll.dll в CE6 (я не помню, где я это видел). Таким образом, ваше устройство Windows Mobile 6, вероятно, будет экспортировано из другого места. (возможно, storeapi.dll?)

Попробуйте создать проект С++ с помощью этого кода и посмотрите, работает ли он для вас:

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