Форматирование раздела API-функциями

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Форматирование раздела API-функциями

Сообщение ger_kar » 12.04.2012 (Чт) 22:28

sosed213 писал(а):Сделал вот так:
Это же не все. Это только декларации, а где вызовы?
Бороться и искать, найти и перепрятать

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 12.04.2012 (Чт) 22:35

Вот же:

Код: Выделить всё
Dim sDriveRoot As String
Dim sFS As String

sDriveRoot = StrConv(CStr(DriveRoot), vbUnicode)
sFS = StrConv("NTFS" & Chr(0), vbUnicode)

Call FormatEx2(ByVal StrPtr(sDriveRoot), _
              FMIFS_HARDDISK, _
              ByVal StrPtr(sFS), _
              ByVal VarPtr(vFormat), _
              AddressOf Callback.FormatExCallBack)
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Форматирование раздела API-функциями

Сообщение ger_kar » 12.04.2012 (Чт) 22:55

Преобразования никакие не нужны, VB и так хранит строки в Юникоде, поэтому их надо убрать.
Потом, что передается в sDriveRoot, строка вида "C:"?
Может проще прислать кусок кода, который можно вставит в модуль как есть, протестить, компилировать, загнать в отладчик, посмотреть что происходит там?
Бороться и искать, найти и перепрятать

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 12.04.2012 (Чт) 22:58

Отправляю исходник, думаю разберешься там что к чему.
Вложения
FormatedEX.zip
Будьте осторожны при запуски
(68.21 Кб) Скачиваний: 110
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 13.04.2012 (Пт) 14:34

Делаю Класс-Модуль для работы с дисками/разделами.

Выкладываю исходник, (может быть станет "кирпичиком", с одобрения "Гуру").

Буду рад содействию, особенно по функции FormatEX2.
Вложения
FormatedEX.zip
(129 Кб) Скачиваний: 95
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Просьба о помощи

Сообщение sosed213 » 14.04.2012 (Сб) 23:01

Кто владеет навыками отладки, помогите узнать, какие значения параметров передаются в функцию FormatEx2 (FMIFS.DLL), при помощи стандартного окна форматирования (в Windows)?

Вот примерная структура функции (примерная, потому что не документированная):

Код: Выделить всё
typedef void (STDAPICALLTYPE *PFORMATEX2)
(IN PWSTR pDrive, IN FMIFS_MEDIA_TYPE dwMediaType, IN PWSTR
pFileSystem,
  IN PFORMATEX2PARAM pFormatEx2Param, IN PFMIFSCALLBACK Callback);
with
typedef struct _FORMATEX2PARAM
{
        int nMajorVersion;
        long nFlags;
        PWSTR pVolumeLabel;
        DWORD dwClusterSize;
        int nVersion;


А вот как делаю я:

Код: Выделить всё
Public Type FormatEx2Param
    nMajorVersion   As Long
    nFlags          As Long
    pVolumeLabel    As Long
    dwClusterSize   As Long
    nVersion        As Long
End Type

Public Declare Sub FormatEx2 Lib "FMIFS.DLL" _
                        (ByVal pDrive As Long, _
                        ByVal dwMediaType As Long, _
                        ByVal pFileSystem As Long, _
                        ByVal pFormatEx2Param As Long, _
                        ByVal Callback As Long)



P.S. Есть похожая функция FormatEx, она работает нормально.
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 16.04.2012 (Пн) 12:57

Хм, может этот вопрос уже в раздел Работа перенести, или самому учиться "дебагить", но это долго :(
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Форматирование раздела API-функциями

Сообщение ger_kar » 17.04.2012 (Вт) 22:36

sosed213 писал(а):P.S. Есть похожая функция FormatEx, она работает нормально.
Если есть нормально работающая, то чем она не устраивает?
sosed213 писал(а):какие значения параметров передаются в функцию FormatEx2 (FMIFS.DLL), при помощи стандартного окна форматирования (в Windows)
Нифига такая ф-ция не вызывается, если открыть консоль для форматирования ее там даже в импортах нет. А откуда такая информация, что именно эта ф-ция вызывается для стандартного форматирования? И еще, отладку с форматированием проводить может быть весьма фатальным для данных занятием. Одна ошибка, даже случайная и геммора на месяц хватит.
Depends Walker 'ром Умеешь пользоваться? Если не умеешь, то научиться одного часа с лихвой хватит. Потом можно будет скачивать различный софт в котором есть функция форматирования и смотреть задействована ли там эта ф-ция, а потом можно и дебагнуть. А сейчас что дебажить MMC консоль что-ли?
Бороться и искать, найти и перепрятать

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 18.04.2012 (Ср) 4:27

Единственное неудобство функции FormatEx да и наверно FormatEx2 (на мой взгляд), что раздел должен быть обязательно смонтирован, т.е. иметь путь или F:\ или \\.\Volume...

Когда я создаю раздел, при помощи IOCTL_DISK_SET_DRIVE_LAYOUT_EX, винда сразу пытает смонтировать и назначить букву этому разделу. Естественно он будет еще не отформатирован, и винда сразу вывалит сообщение: Диск не отформатирован, отформатировать? Хотя через пару секунд я его уже отформатирую программно, а окно с предложением отформатировать останется висеть.

Можно конечно применить и "грязный" способ, постоянно искать и прибивать виндовые окна предлагающие форматировать, но это последнее чем хотелось бы пользоваться.

Вот например Diskpart.exe при создании раздела, может его форматировать даже не имея буквы у раздела, и что то мне подсказывает что он пользуется не функцией FormatEx и даже наверно не FormatEx2.

Вот с него я наверно и начну изучать программу Depends Walker

Спасибо ger_kar
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 18.04.2012 (Ср) 13:11

Ха-Ха, Diskpart.exe - обманщик :lol:

При создании раздела разделу тоже сначала присваивается буква, а Diskpart потом ее быстренько удаляет :lol:

Только, теперь интересно, как в его случае винда не вываливает окно с предложением отформатировать том?! Может Diskpart отключает временно Broadcast ...
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 18.04.2012 (Ср) 13:46

Кажется все ясно, только осталось проверить.

При создании раздела, нужно устанавливать флаг RecognizedPartition = False

PARTITION_INFORMATION_MBR structure или PARTITION_INFORMATION structure
RecognizedPartition
Indicates, when TRUE, that the system recognized the type of the partition. When FALSE, the system did not recognize the type of the partition.
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 30.04.2012 (Пн) 18:24

Не могу найти решение - чувствую себя идиотом.
Нахожу решение - чувствую себя идиотом.
Хм - чувствую себя идиотом.
:|
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Форматирование раздела API-функциями

Сообщение ger_kar » 30.04.2012 (Пн) 21:42

И какое решение нашлось?
Бороться и искать, найти и перепрятать

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 01.05.2012 (Вт) 7:09

Расскажу по порядку.
Как оказалось RecognizedPartition, не влияет на то, будет ли система предлагать отформатировать диск перед его использованием или нет.
Ну это я обхожу грязным методом, нахожу и прибиваю это окно.

Теперь, в чем у меня основной затык:
Диск может быть инициализирован как MBR так и GPT (рекомендуется при объеме диска >2Tb).
MBR диск может содержать до 4 основных разделов, один из которых может быть расшириным, и содержать в себе еще 4 логических разделов, итого максимум 7 разделов. Но расшириныые и логические меня пока вообще не волнуют.

GPT диск может содержать (помойму) только основные разделы, и максимальное количество достигает 128-разделов.

Теперь о грустном. Каждый раздел на диске(MBR и GPT) имеет два важных (для меня) параметра: Offset и Len, то есть отступ и длина.
Для создания разделов я пишу функцию у которой есть куча входных параметров (таких как номер диска, возможный размер раздела (если 0, то занять все доступное пространство), возможное смещение или Offset (если 0, то начинать с первого незанятого пространства на диске), ФС и Букву диска, размер кластера, быстрое форматирование(True/False), и несколько еще незначительных ) и два выходных параметра, один значение самой функции, если <0 то неудача и код ошибки, если > 0 то успех, и смотрим на ByRef переменную в которую возвращается значение с именем Буквы созданного раздела или точку монтирования.

В теле самой функции начинается куча всяких проверок:
    -доступен ли диск;
    -не превышает ли offset+len+1mb общего размера диска;
    -Если на диске уже есть разделы, то сумма всех разделов по объему, вместит ли еще один раздел заданного объема;
    -Если на диске уже есть раздела, то если диск MBR, не превышено ли количество основных разделов четырех, или в случае с GPT – 128 разделов (хотя у GPT дисков есть такой параметр MaxPartitionCount, вероятно оно может быть меньше 128);
    -Если диск еще не инициализирован, то если во входящих параметрах функции явно не задан каким типом должен быть инициализирован жесткий диск, то смотрится на его размер, если меньше 2TB то нужно инициализировать в MBR, иначе в GPT;

Дальше начинается самое интересное. Смотря в диспетчер управления дисками, я вижу где можно создать раздел, какой длинны, и с каким смещением, но программно это реализовать пока не могу, видимо в силу отсутствия нужной мысли и логики.
Ведь разделы могу быть разбросаны по диску как угодно, между разделами может присутствовать свободное пространство, где может запросто уместиться создаваемый раздел.
Я вижу два варианта решения этой задачи:
    1. представить жесткий диск в виде оси OX, а разделы отрезки на ней, но у меня с арифметикой не очень, не знаю что делать дальше.
    2. Организовать некий алгоритм ветвления который будет попорядку перебирать разделы, и смотреть, возможно ли уместить раздел перед выбранным разделом, или после.

Я пока остановился на втором варианте, но он у меня такой корявый… Если всегда задаю смещение=0, то в принципе все проходит «неплохо», но в случае с векторами можно было бы легко проверять лежит ли точка offset на каком то из имеющихся разделов или нет.

Если на каком то этапе возникли проблемы, то функция завершает свое выполнение, и возвращает отрицательное значение с номером этапа (например -2 значит не удалось открыть диск CreateFile)

Уже примерно неделю ничего не пишу, а лишь в голове пережевываю этот алгоритм. И не надеюсь что кто то станет убивать свое время чтобы помочь мне разобраться, просто иногда надо все кому то рассказать, чтобы самому понять.

P.S.
Основная информация, на основе которой проводятся все проверки, хранятся в переменной Dim DL As DRIVE_LAYOUT_INFORMATION_EX и принимает она значение при помощи управляющего кода IOCTL_DISK_GET_DRIVE_LAYOUT_EX


Код: Выделить всё
Public Type DRIVE_LAYOUT_INFORMATION_MBR
    Signature   As Long
End Type

Public Type PARTITION_INFORMATION_MBR
    PartitionType    As Byte             'FAT32=0x0B
    BootIndicator    As Byte       
    Recognized       As Integer
    HiddenSectors   As Long  'LARGE_LONG
End Type

Public Type PARTITION_INFORMATION_GPT
    PartitionType   As GUID
    PartitionId       As GUID
    Attributes        As LARGE_INTEGER    'DWord64
    mName(35)      As Integer
End Type

Public Type PARTITION_INFORMATION_EX
    PartitionStyle              As Long    'PARTITION_STYLE
    OffSet                        As LARGE_INTEGER
    Size                           As LARGE_INTEGER
    PartitionNumber         As Long
    RewritePartition         As Byte
    Union_Part_Mbr_Gpt  As PARTITION_INFORMATION_GPT
End Type

Public Type DRIVE_LAYOUT_INFORMATION_GPT   
    DiskId                          As GUID
    StartingUsableOffset    As LARGE_INTEGER
    UsableLength               As LARGE_INTEGER
    MaxPartitionCount       As Long
End Type

Public Type DRIVE_LAYOUT_INFORMATION_EX
    PartitionStyle           As Long 'PARTITION_STYLE
    PartitionCount          As Long
    Union_Driver_Mbr_Gpt    As DRIVE_LAYOUT_INFORMATION_GPT
    Partitions(127)     As PARTITION_INFORMATION_EX
End Type

    Dim dwOutBytes  As Long
    Dim DL          As DRIVE_LAYOUT_INFORMATION_EX
    Dim retIOCTL    As Long
       
    retIOCTL = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, ByVal 0&, 0, DL, LenB(DL), dwOutBytes, ByVal 0&)
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

DarthTon
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 29.05.2012 (Вт) 17:46

Re: Форматирование раздела API-функциями

Сообщение DarthTon » 29.05.2012 (Вт) 17:51

У меня есть реализация создания раздела с 0 и его форматирования через FormatEx на С++, если надо, могу выложить.

sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 30.05.2012 (Ср) 5:02

DarthTon, да, было бы здорово. мне важно понять логику проверки можно ли создать раздел, есть ли свободное для него место, и удовлетворяются ли все условия.

А вообще, прежде чем вносить какие то изменения в разметку HDD, надо определить возможность создания, например, 3-х разделов.
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

DarthTon
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 29.05.2012 (Вт) 17:46

Re: Форматирование раздела API-функциями

Сообщение DarthTon » 31.05.2012 (Чт) 11:39

Краткое описание работы кода:

1. Переключить диск в онлайн режим(необходимо если изначально диск оффлайн, так как с офлайновыми нельзя ничего сделать).
2. Создать MBR.
3. Создать таблицу разделов (всего 1 раздел который занимает всё доступное место на диске).
4. Получить GUID созданного раздела.
5. Присвоить разделу букву (FormatEx у меня упорно не хочет форматировать раздел если подавать ей на вход GUID а не букву).
6. Форматировать раздел в NTFS.

Код: Выделить всё
/*
    Control codes used while bringing disk online
*/
#define IOCTL_DISK_GET_DISK_ATTRIBUTES      CTL_CODE(IOCTL_DISK_BASE, 0x003c, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DISK_SET_DISK_ATTRIBUTES      CTL_CODE(IOCTL_DISK_BASE, 0x003d, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

#define DISK_ATTRIBUTE_OFFLINE              0x1
#define DISK_ATTRIBUTE_READ_ONLY         0x2

/*
    Structure used while bringing disk Online
*/
typedef struct _SET_DISK_ATTRIBUTES
{
    ULONG Version;                            //Structure size
    BOOLEAN Persist;                         //Remain after reboot
    BOOLEAN RelinquishOwnership;     //Release previously received ownership
    BOOLEAN Reserved1[2];                //Padding
    ULONGLONG Attributes;                //Attributes(DISK_ATTRIBUTE_OFFLINE,DISK_ATTRIBUTE_READ_ONLY)
    ULONGLONG AttributesMask;        //Attributes mask
    GUID Owner;                                //Owner GUID
} SET_DISK_ATTRIBUTES, *PSET_DISK_ATTRIBUTES;


typedef enum
{
    PROGRESS,
    DONEWITHSTRUCTURE,
    UNKNOWN2,
    UNKNOWN3,
    UNKNOWN4,
    UNKNOWN5,
    INSUFFICIENTRIGHTS,
    UNKNOWN7,
    UNKNOWN8,
    UNKNOWN9,
    UNKNOWNA,
    DONE,
    UNKNOWNC,
    UNKNOWND,
    OUTPUT,
    STRUCTUREPROGRESS
} CALLBACKCOMMAND;

typedef BOOLEAN (__stdcall *PFMIFSCALLBACK)( CALLBACKCOMMAND Command, DWORD SubAction, PVOID ActionInfo );

// Format command in FMIFS
//

// media flags
#define FMIFS_HARDDISK 0xC
#define FMIFS_FLOPPY   0x8

typedef VOID (__stdcall *PFORMATEX)( PWCHAR DriveRoot,
                                    DWORD MediaFlag,
                                    PWCHAR Format,
                                    PWCHAR Label,
                                    BOOL QuickFormat,
                                    DWORD ClusterSize,
                                    PFMIFSCALLBACK Callback );


bool bFormatSuccess = false;

/*
    Retrieves just all volume GUIDs
*/
void GetVolumeGUIDS( std::vector<std::wstring>& pVec )
{
    DWORD dwResult = ERROR_SUCCESS;

    HANDLE FindHandle                      = INVALID_HANDLE_VALUE;
    BOOL   Success                             = FALSE;
    WCHAR  VolumeName[MAX_PATH] = L""; 

    //  Enumerate all volumes in the system.
    FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));

    if (FindHandle == INVALID_HANDLE_VALUE)
        return;

    for (;;)
    {
        pVec.push_back(std::wstring(VolumeName));

        //  Move on to the next volume.
        Success = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));

        if ( !Success )
        {
            dwResult = GetLastError();

            if (dwResult != ERROR_NO_MORE_FILES)
            {
                dwResult = GetLastError();
                break;
            }

            // Finished iterating through all the volumes.
            dwResult = ERROR_SUCCESS;
            break;
        }
    }

    FindVolumeClose(FindHandle);
}

/*
    Removes previously available volumes from container
*/
void FilterGuids( std::vector<std::wstring> vecCurrent, std::vector<std::wstring>& vecDiff )
{
    std::vector<std::wstring> vecNewGUIDs;
    std::vector<std::wstring> vecTmp;
    bool bPresent = false;

    GetVolumeGUIDS(vecNewGUIDs);

    for(DWORD i=0;i<vecNewGUIDs.size();i++)
    {
        bPresent = false;

        for(DWORD j=0;j<vecCurrent.size();j++)
            if(vecCurrent[j].compare(vecNewGUIDs[i])==0)
            {
                bPresent = true;
                break;
            }

        if(!bPresent)
            vecTmp.push_back(vecNewGUIDs[i]);       
    }

    vecDiff = vecTmp;
}

/*
    Assigns letter to a volume by its GUID

    IN:
        wszGUID - volume GUID
        pwsLetter - pointer to variable that will receive letter
        maxlen - max size of pwsLetter

    OUT:
        pwsLetter - assigned letter

    Return:
        Error code
*/
DWORD AssignLetter( const wchar_t* wszGUID, wchar_t* pwsLetter, int maxlen )
{
    BOOL bResult = FALSE;
    DWORD dwByteCount = 0;              //Returned bytes count
    DWORD dwCounter =0;

    //Obtain volume letter from GUID
    bResult = GetVolumePathNamesForVolumeNameW(wszGUID, pwsLetter, maxlen, &dwByteCount);

    //Assign letter to volume
    if(wcslen(pwsLetter)==0)
    {
        //Retrieve bitmap of used letters
        DWORD dwUsedLetters =  GetLogicalDrives();     

        //starting from C:\ (3rd drive)
        DWORD dwCurrLetterBit = 1<<2;                       

        //Get first unused letter
        while(dwUsedLetters & dwCurrLetterBit)
        {
            //Move to next drive bit
            dwCurrLetterBit <<= 1;
            dwCounter++;
        }

        //Print letter
        StringCbPrintfW(pwsLetter, maxlen, L"%c:\\", dwCounter+67);

        //Assign letter to volume
        bResult = SetVolumeMountPointW(pwsLetter, wszGUID);
        if(!bResult)
            return GetLastError();
    }

    return ERROR_SUCCESS;
}

/*
    Callback for FormatEx function

    IN:
        Command - callback command
        Modifier - unknown
        Argument - pointer to callback data

    Return:
        Error code
*/
BOOLEAN __stdcall FormatExCallback( CALLBACKCOMMAND Command, DWORD Modifier, PVOID Argument )
{
    PBOOLEAN status = NULL;

    // We get other types of commands, but we don't have to pay attention to them
    if(Command == DONE)
    {
        status = (PBOOLEAN) Argument;
        if( *status == FALSE )
        {
            DWORD dwErr = GetLastError();

            //Sometimes function finishes with FALSE status, but formats partition
            //If partition was formatted, last error is not 0
            if(dwErr != ERROR_SUCCESS)
            {
                bFormatSuccess = false;
                return FALSE;
            }
        }
        else
        {
            bFormatSuccess = true;
            return TRUE;
        }
    }

    return TRUE;
}

/*
    Performs partition format

    IN:
        pwszName - partition letter

    OUT:
        void

    Return:
        Error code
*/
DWORD FormatVolume(wchar_t* pwszName )
{
    DWORD dwResult = ERROR_SUCCESS;
    DWORD dwRetries = 3;

    //Load dll containing format function
    HMODULE hDll = LoadLibrary("fmifs.dll");
    if(!hDll)
        return GetLastError();

    PFORMATEX FormatEx = (PFORMATEX)GetProcAddress(hDll, "FormatEx");
    if(!FormatEx)
    {
        FreeLibrary(hDll);
        return GetLastError();
    }

    bFormatSuccess = false;
    SetLastError(ERROR_SUCCESS);

    //Perform quick format to NTFS with default cluster size
    FormatEx(pwszName, FMIFS_HARDDISK, L"NTFS", L"Label", TRUE, 0,FormatExCallback);

    //Retry format in case of fail. Sometimes partition is formatted only on second run
    while (!bFormatSuccess && dwRetries > 0)
    {
        Sleep(100);
        dwRetries--;

        bFormatSuccess = false;
        SetLastError(ERROR_SUCCESS);

        FormatEx(pwszName, FMIFS_HARDDISK, L"NTFS", L"Label", TRUE, 0,FormatExCallback);       
    }

    FreeLibrary(hDll);

    return dwResult;
}

/*
    Partitions attached disk and creates NTFS volume

    IN:
        dDrive - zero-based PhysicalDrive number

    OUT:
        void

    Return:
        Error code

*/
DWORD CreateVolume( HANDLE hDrive )
{
    DWORD dwResult = ERROR_SUCCESS;

    GET_LENGTH_INFORMATION DiskLength = {0};                    //Disk size
    HANDLE hDevice = hDrive;                                    //Disk device handle
    BOOL bResult = 0;                                           //Function call result
    DWORD junk = 0;                                             //bytes received
    DRIVE_LAYOUT_INFORMATION_EX *pLayoutInfo;                   //Partitioning structure
    DWORD dwStructSize = 0;                                     //size of pLie
    CREATE_DISK disk;                                           //MBR sector info
    SET_DISK_ATTRIBUTES sda = {0};                              //Used to bring disk online
    std::vector<std::wstring> vecGUIDs;                         //List of volumes in system

    //Enumerate present volumes before creating new
    GetVolumeGUIDS(vecGUIDs);

    //Required size for 4 partitions
    dwStructSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX)+3*sizeof(PARTITION_INFORMATION_EX);
    pLayoutInfo = (DRIVE_LAYOUT_INFORMATION_EX*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, dwStructSize);

    if(hDevice==INVALID_HANDLE_VALUE)
        return GetLastError();

    ZeroMemory(&disk,sizeof(CREATE_DISK));

    disk.PartitionStyle = PARTITION_STYLE_MBR;
    disk.Mbr.Signature = GetTickCount();    //signature
   
    //Some values got from experimenting, and they work
    sda.Version = sizeof(sda);
    sda.Persist = 1;
    sda.RelinquishOwnership = FALSE;
    sda.Attributes = 0;
    sda.AttributesMask = 3;

    //Bring disk online and clear read-only flag
    bResult = DeviceIoControl(hDevice,IOCTL_DISK_SET_DISK_ATTRIBUTES,&sda,sizeof(sda), NULL, 0,&junk,NULL);
    if(!bResult)
    {
        if(pLayoutInfo)
            HeapFree(GetProcessHeap(),0,pLayoutInfo);

        return GetLastError();
    }

    //Get disk size
    bResult = DeviceIoControl(hDevice,IOCTL_DISK_GET_LENGTH_INFO,NULL,0, &DiskLength, sizeof(GET_LENGTH_INFORMATION),&junk,NULL);
    if(!bResult)
    {
        if(pLayoutInfo)
            HeapFree(GetProcessHeap(),0,pLayoutInfo);

        return GetLastError();
    }

    //Create MBR
    bResult = DeviceIoControl(hDevice,IOCTL_DISK_CREATE_DISK,&disk,sizeof(CREATE_DISK),NULL, 0,&junk,NULL);
    if(!bResult)
    {
        if(pLayoutInfo)
            HeapFree(GetProcessHeap(),0,pLayoutInfo);

        return GetLastError();
    }

    //Get new device properties
    bResult = DeviceIoControl(hDevice,IOCTL_DISK_UPDATE_PROPERTIES,NULL,0,NULL, 0,&junk,NULL);
    if(!bResult)
    {
        if(pLayoutInfo)
            HeapFree(GetProcessHeap(),0,pLayoutInfo);

        return GetLastError();
    }

    //Fill partition table
    if (hDevice!=INVALID_HANDLE_VALUE)
    {
        //First partition - occupies all available space
        pLayoutInfo->PartitionEntry[0].PartitionStyle = PARTITION_STYLE_MBR;
        pLayoutInfo->PartitionEntry[0].StartingOffset.QuadPart = 1048576;       //1 MB offset
        pLayoutInfo->PartitionEntry[0].PartitionLength.QuadPart = DiskLength.Length.QuadPart - 1048576 - 2048*512;
        pLayoutInfo->PartitionEntry[0].PartitionNumber = 1;
        pLayoutInfo->PartitionEntry[0].RewritePartition = TRUE;
        pLayoutInfo->PartitionEntry[0].Mbr.PartitionType = PARTITION_IFS;       //valid NTFS partition
        pLayoutInfo->PartitionEntry[0].Mbr.BootIndicator = FALSE;
        pLayoutInfo->PartitionEntry[0].Mbr.RecognizedPartition = 1;
        pLayoutInfo->PartitionEntry[0].Mbr.HiddenSectors = /*32256/512*/2048;   //Vista style partitioning

        //Fill unused partitions info
        for(int i=1;i<4;i++)
        {
            pLayoutInfo->PartitionEntry[i].PartitionStyle = PARTITION_STYLE_MBR;
            pLayoutInfo->PartitionEntry[i].PartitionNumber = i+1;
            pLayoutInfo->PartitionEntry[i].Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
        }

        pLayoutInfo->PartitionStyle = PARTITION_STYLE_MBR;
        pLayoutInfo->PartitionCount = 4;                       //must be exactly 4
        pLayoutInfo->Mbr.Signature = GetTickCount();

        //Set partition layout
        bResult = DeviceIoControl(hDevice,IOCTL_DISK_SET_DRIVE_LAYOUT_EX,pLayoutInfo,dwStructSize,NULL,0,&junk,NULL);

        if(bResult)
        {
            wchar_t wszLetter[4];
            DWORD dwTimeout = 20 * 1000;          //20 sec.
            std::vector<std::wstring> vecDiff;    //New volume GUID

            DeviceIoControl(hDevice,IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0,NULL,0,&junk,NULL);

            if(pLayoutInfo)
                HeapFree(GetProcessHeap(),0,pLayoutInfo);
   
            //Wait for system to find new volume
            FilterGuids(vecGUIDs, vecDiff);

            while (vecDiff.size() == 0 && dwTimeout > 0)
            {
                dwTimeout -= 100;
                Sleep(100);

                FilterGuids(vecGUIDs, vecDiff);
            }

            //if found new partition
            if(vecDiff.size() > 0)
            {
                dwResult = AssignLetter(vecDiff[0].data(), wszLetter, sizeof(wszLetter));

                //Format partition to NTFS
                if(dwResult==ERROR_SUCCESS)
                    dwResult = FormatVolume(wszLetter);
            }
            else
                dwResult = ERROR_NO_DATA;
        }
        else
        {
            if(pLayoutInfo)
                HeapFree(GetProcessHeap(),0,pLayoutInfo);

           dwResult = GetLastError();
        }
    }

    return dwResult;
}


sosed213
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 206
Зарегистрирован: 13.11.2007 (Вт) 21:19
Откуда: Омск

Re: Форматирование раздела API-функциями

Сообщение sosed213 » 31.05.2012 (Чт) 12:43

DarthTon, спасибо!

Тоже так и не смог заставить FormatEx работать через GUID.
И странно что через SET_DRIVE_LAYOUT_EX система сразу же пытается монтировать раздел. Имхо: двойная работа.

Кстати, DiskPart тоже, по мойму, так же создает разделы. Видно что он создает раздел, моя программа MyDisk говорит что появилась буква, и тут же исчезла.


Вот это для себя полезное подчерпнул: disk.Mbr.Signature = GetTickCount();

Интересно Mbr.Signature, принципиально за что нибудь отвечает, или это просто идентификатор диска, так нигде описания и не нашел.

А тайминги ты приблизительные ставил или где то написано что так и надо?
Не могу сказать что знаю все, но и за дурака прошу меня не считать.

DarthTon
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 29.05.2012 (Вт) 17:46

Re: Форматирование раздела API-функциями

Сообщение DarthTon » 31.05.2012 (Чт) 12:45

Интересно Mbr.Signature, принципиально за что нибудь отвечает, или это просто идентификатор диска, так нигде описания и не нашел.

А тайминги ты приблизительные ставил или где то написано что так и надо?


Это просто идентификатор, а GetTickCount() я использую фактически для генерации случайного числа.

Пред.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот, Yandex-бот и гости: 41

    TopList