This is a code sample to give you an idea how to incorporate a Split function to your solution. The Split functionality is one of the advanced partitioning tasks.

The Split functionality is key to keeping your data storage healthy. Keeping all the data on a single volume negatively affects the system: unorganized storage leads to inevitable excessive fragmentation. As a result, it is difficult to search and access the files, and it hinders the read/write operations. Finally, it can cause serious issues in case of a system malfunction. 

By incorporating the Split functionality into your customized solution you can separate the operating system and data or different types of data by splitting one partition into two different partitions of the same type and file system.

Limitations to consider before proceeding with the Split functionality:

  • Partition’s type is not supported (a non-standard primary or logical partition);
  • The selected partition is located on a dynamic disk;
  • There are 4 primary partitions on a Basic MBR disk;
  • There are 3 primary partitions on a Hybrid (Retained) GPT+MBR disk;
  • There’s not enough free space on the selected partition (free up to 50 MB);
  • The selected partition has an unsupported file system.

Due to internal restrictions, hdmengine cannot work on multiple processes at the same time, so it locks the volume during the process to restrict access from another process. For example, if an additional process is initialized (for example, resize a partition) when the hdmengine is busy with a different process (for example, creating a partition), the engine will not be able to lock the additional process (resize a partition) and will execute it in the Bluescreen mode.

Before you read this code sample: 

  • Include the header files.
  • Add hdmclient_hdmclientlib.dll library to your project.
  • Set up callbacks from hdmclientlib.

For more details on the initial setup, please see the Setting Up the C++ Development Environment section.

Add the header files to copy blocks of memory and pull in the rest of the headers from the clientapp engine, including the callback prototypes.

#include <string.h> // memcpy
 
#include "../hdmclientapp_progress.h"

Set callbacks. You need to implement the abstract interface struct Hdmclient_IProgress.

_Hdmclient_Init                proc_Hdmclient_Init                = NULL;
_Hdmclient_Close               proc_Hdmclient_Close               = NULL;
_Hdmclient_GetInterface        proc_Hdmclient_GetInterface        = NULL;
_Hdmclient_GetLog              proc_Hdmclient_GetLog              = NULL;
_Hdmclient_InstallBluescreen   proc_Hdmclient_InstallBluescreen   = NULL;
_Hdmclient_GetErrorDescription proc_Hdmclient_GetErrorDescription = NULL;

Add a helper function to log output messages. How to set LogPrint please see hdmclientapp_main.cpp or look at a code sample here.

static void LogPrint(Hdmclient_ILog * /* pLog */, bool /* rewrite */, const char * /* format */, IN ...)
{
}

Select the disk number and partition number, you want to split. Set the volume of the left partition in GB, set the right partition letter and label.

HDMCLIENT_ERR Hdmclient_Example_PartitionSplit(unsigned    diskNumber, 
                                               unsigned    partNumber,   
                                               unsigned    sizeParentGB,
                                               const char *pChildLabel,
                                               const BYTE  childLetter)

Set the variables for the error code, whether a reboot is necessary, and interfaces to log the actions as well as the interface to implement callbacks.

{
    HDMCLIENT_ERR err = SERR_SUCCESS;
 
    BOOL bReboot = FALSE;
 
    Hdmclient_ILog *pLog = NULL;
 
    Hdmclient_Progress hdmclientProgress;

Set the hdmengine initialization flags and enable run multiple instances of Hdmengine application.

    if(!err)
    {
        unsigned int initFlags = Hdmclient_InitFlags::Hdmclient_InitFlag_EnableRunMultiple;

Initialize Hdmengine API: pass engine flags, pass the progress interface to Hdmengine API, pass the application log path. Then get the logging interface.

        err = proc_Hdmclient_Init((Hdmclient_InitFlags)initFlags,
                              &hdmclientProgress,           
                              "hdmclient_hdmclientapp.log",
                              NULL, NULL, NULL);
 
        if(!err)
        proc_Hdmclient_GetLog(&pLog);
    }

Get the partitioning interface.

    if(!err)
    {
        Hdmclient_IInterface* pInterface = NULL;
        if(!err)
            err = proc_Hdmclient_GetInterface(&pInterface);

Search for the selected partition by disk and partition number (all numbers zero based, extended and free partitions are also counted). Hdmclient_IInterface::DiskInfo diskInfo = {}; – Displays selected disk info and Hdmclient_IInterface::PartitionInfo partInfo displayed selected partition info.

        Hdmclient_IInterface::DiskInfo      diskInfo = {};
        Hdmclient_IInterface::PartitionInfo partInfo = {};
 
        if(!err)
        {
            Hdmclient_IInterface::EnumDisksInfo* enumDisksInfo = NULL;

Get the disks enumerator and release the disks enumerator.

            err = pInterface->GetDisksInfo(&enumDisksInfo);
            if(!err)
            {
                if(enumDisksInfo && (enumDisksInfo->disksCount > 0))
                {
                    if(!err)
                    {
                        if(diskNumber == (unsigned)-1)
                        {
                            err = SERR_DISK_NOT_FOUND;
 
                            LogPrint(pLog, false, "Disk is not selected .. Failed\n");
                        }else
                        if((diskNumber + 1) > enumDisksInfo->disksCount)
                        {
                            err = SERR_DISK_NOT_FOUND;
 
                            LogPrint(pLog, false, "Disk number is out of range (maximum number is %lu) .. Failed\n", enumDisksInfo->disksCount - 1);
                        }else
                        {
                            auto pDiskInfo = enumDisksInfo->ppDisksInfo[diskNumber];
 
                            memcpy(&diskInfo, pDiskInfo, sizeof(diskInfo));
 
                            if(partNumber != (unsigned)-1)
                            {
                                if((partNumber + 1) <= pDiskInfo->enumPartitionsInfo.partitionsCount)
                                {
                                    auto pPartitionInfo = pDiskInfo->enumPartitionsInfo.ppPartitionsInfo[partNumber];
 
                                    memcpy(&partInfo, pPartitionInfo, sizeof(partInfo));
                                }else
                                {
                                    err = SERR_PART_NOT_FOUND;
 
                                    LogPrint(pLog, false, "Partition number is out of range (maximum number is %lu) .. Failed\n", pDiskInfo->enumPartitionsInfo.partitionsCount - 1);
                                }
                            }
                        }
                    }
                }
 
                pInterface->ReleaseDisksInfo(enumDisksInfo);
            }
        }

Verify that you can split the selected partition or disk.

        if(!err)
        {
            if(!(partInfo.ActFlags & Hdmclient_IInterface::PartitionActFlags::PartitionActFlag_Can_SplitFs))
            {
                err = SERR_INCOMPATIBLEOP;
 
                LogPrint(pLog, false, "Split file system is not enabled for selected partition ... Failed\n");
            }else

Perform the virtual step for split action. User custom size or MinSize + 10 GB.

            {
                UINT64 partParentSizeBytes = (sizeParentGB != 0) ? ((UINT64)sizeParentGB * BYTES_IN_GB) : (partInfo.MinSizeBytes + ((UINT64)10 * BYTES_IN_GB));
 
                BYTE partLetter = 0;
 
                if(((childLetter >= 'A') && (childLetter <= 'Z')) ||
                   ((childLetter >= 'a') && (childLetter <= 'z')))
                    partLetter = childLetter;
                else
                if(childLetter == '*')
                    partLetter = pInterface->GetNextAvailableDriveLetter();

Add file masks to skip from split partition (will remain on original volume).

                const char* sExcludeFileMasks = "/Excluded data dir0\0/Excluded data dir1\0*.exe\0\0";

Add file masks that will be moved to child partition after split. Perform the split (virtual step).

                const char* sSplitFileMasks = "/Splitted data dir0\0/Splitted data dir1\0\0";
 
                err = pInterface->Partition_SplitFs(partInfo.DiskNumber,
                                            partInfo.PartitionNumber,
                                            partParentSizeBytes,
                                            partLetter,
                                            (const BYTE*)pChildLabel,
                                            sExcludeFileMasks,
                                            sSplitFileMasks);
 
                LogPrint(pLog, false, "Splitting selected partition file system ... %s\n", err ? "Failed" : "Success");
            }
        }

Then perform the split action (physical step) and apply the queue or above operations if it was scheduled.

        if(!err)
        {
            if(!err)
            {
                LogPrint(pLog, false, "Applying operations ...\n");
 
                err = pInterface->Apply();
 
                if(!err)
                {
                    LogPrint(pLog, false, "Applying queue of operations ... Success\n");
                }else
                {
                    LogPrint(pLog, false, "Applying queue of operations ... Failed (Result: 0x%x, \"%s\")\n", err, proc_Hdmclient_GetErrorDescription(err));
                }
            }
        }
    }

Close the HDM client API.

    proc_Hdmclient_Close(bReboot, FALSE);

    return err;
}

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Summary
Article Name
HDM Split Functionality in C++