Mapping VolumeID to Disk partition Using the DeviceIOControl API

 

To map a volume with drive letter to disk partition, one may use some combination of WMI classes like

Win32_LogicalDisk,Win32_LogicalDiskToPartition,Win32_DiskPartition, Win32_DiskDriveToDiskPartition and Win32_DiskDrive.

Unfortunately WMI does not provide a way to map a disk partition that does not have a drive letter associated with it. There is no WMI class to associate a disk volume to disk partition directly. However, one can use the low level DeviceIoControl API to request disk partition information directly from the disk device driver.

Below is a sample program to list all the volumeIDs with corresponding partitions and steps to build the sample using WDK.

 

1) Download and install the WDK from www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=36a2630f-5d56-43b5-b996-7633f2ec14ff

 

2) Start a command prompt and go to the bin directory in WinDDK installtion folder and run setenv.bat for whatever system you are building for, for example:

setenv C:\WinDDK\7268.0.0 chk WNET

3) At this point you have a build environment pointing to the WDK install folders created within the CMD window.

4) Create a folder named 'mounts' in the build environment folder created in step 3 (in this example C:\WinDDK\7268.0.0) and create following files in it

                * A Header file named 'enumvol.h' using the code snippet given below under enumvol.h header

                * A 'C' source file named 'mounts.c' using code snippet given below under 'mounts.c'header

                * A 'MakeFile' file named 'MakeFile'using the text given under header 'MakeFile' header

                * A 'Source' file named 'Source'using the text given under 'Source'header

5) Navigate to the folder created in step 4 and run “bcz”, this will create an executable file that will display the disk partition information.

 

 

Source Files

================

'===================================================================
' DISCLAIMER:
'-------------------------------------------------------------------
'
' This sample is provided as is and is not meant for use on a
' production environment. It is provided only for illustrative
' purposes. The end user must test and modify the sample to suit
' their target environment.
'
' Microsoft can make no representation concerning the content of
' this sample. Microsoft is providing this information only as a
' convenience to you. This is to inform you that Microsoft has not
' tested the sample and therefore cannot make any representations
' regarding the quality, safety, or suitability of any code or
' information found here.
'
'===================================================================

/**************************************************enumvol.h************************************************/

#ifndef _ENUMVOL_H_

#define _ENUMVOL_H_

//

// Command Descriptor Block constants.

//

#define CDB6GENERIC_LENGTH 6

#define CDB10GENERIC_LENGTH 10

#define SCSIOP_INQUIRY 0x12

#define BUF_LEN (8*1024)

#define DIRECT_ACCESS_DEVICE 0

// Define constants for \DosDevices\X:

#define DOSDEVICES_LENGTH 12

#define DRIVE_LETTER_LENGTH 14

#define DRIVE_LETTER_POSITION 12

#define DRIVE_COLON_POSITION 13

                               

#define MOUNTMGR_NAME "\\\\.\\MountPointManager"

//

// Bus Type

//

static char* BusType[] = {

    "UNKNOWN", // 0x00

    "SCSI",

    "ATAPI",

    "ATA",

    "IEEE 1394",

    "SSA",

    "FIBRE",

    "USB",

    "RAID"

};

//

// SCSI Device Type

//

static char* DeviceType[] = {

    "Direct Access Device", // 0x00

    "Tape Device", // 0x01

    "Printer Device", // 0x02

    "Processor Device", // 0x03

    "WORM Device", // 0x04

    "CDROM Device", // 0x05

    "Scanner Device", // 0x06

    "Optical Disk", // 0x07

    "Media Changer", // 0x08

    "Comm. Device", // 0x09

    "ASCIT8", // 0x0A

    "ASCIT8", // 0x0B

    "Array Device", // 0x0C

    "Enclosure Device", // 0x0D

    "RBC Device", // 0x0E

    "Unknown Device" // 0x0F

};

typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {

    SCSI_PASS_THROUGH Spt;

    ULONG Filler; // realign buffers to double word boundary

    UCHAR SenseBuf[32];

    UCHAR DataBuf[512];

} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;

VOID PrintError( ULONG );

BOOL GetDeviceProperty( HDEVINFO, DWORD );

VOID DebugPrint( USHORT, PCHAR, ... );

void PrintMountName(PMOUNTDEV_NAME mountName);

void PrintName(PWCHAR Name, USHORT Len);

void GetDriveLetter(PMOUNTDEV_NAME mountName);

void GetVolumeExtents(PWCHAR volumeGuid);

BOOL IsDriveLetter(PWCHAR Name, USHORT Len);

BOOL IsVolumeGuid(PWCHAR Name, USHORT Len);

#endif // _ENUMVOL_H_

/**************************************************enumvol.h************************************************/

/**************************************************mounts.c*************************************************/

#include <stdio.h>

#include <stdlib.h>

#include <stddef.h>

#include <windows.h>

#include <initguid.h> // Guid definition

#include <devguid.h> // Device guids

#include <setupapi.h> // for SetupDiXxx functions.

#include <cfgmgr32.h> // for SetupDiXxx functions.

#include <devioctl.h>

#include <ntdddisk.h>

#include <ntddvol.h>

#include <ntddscsi.h>

#include <mountdev.h>

#include <mountmgr.h>

#include <enumvol.h>

BOOL GetStorageDeviceNumber(HANDLE device, PSTORAGE_DEVICE_NUMBER number)

{

    BOOL status;

    unsigned long returned_bytes;

    //unsigned long returned_bytes, errno;

    status = DeviceIoControl(device,

                             IOCTL_STORAGE_GET_DEVICE_NUMBER,

                             NULL,

                             0,

                             number,

                             sizeof(STORAGE_DEVICE_NUMBER),

                             &returned_bytes,

                             FALSE);

               

    if (!status) {

        errno = GetLastError();

        //printf("Error getting storage device number: status %d, returned %d\n", errno, returned_bytes);

        return FALSE;

    } else {

        //printf("got storage device number: disk%d, part%d\n",

        // number->DeviceNumber, number->PartitionNumber);

    }

   

    return TRUE;

}

BOOL GetPartitionInfoEx(HANDLE device, PPARTITION_INFORMATION_EX PartInfo)

{

    BOOL status;

    unsigned long returned_bytes;

    //unsigned long returned_bytes, errno;

    status = DeviceIoControl(device,

                             IOCTL_DISK_GET_PARTITION_INFO_EX,

                             NULL,

                             0,

                             PartInfo,

                             sizeof(PARTITION_INFORMATION_EX),

                             &returned_bytes,

                             FALSE);

               

    if (!status) {

        errno = GetLastError();

        //printf("Error getting partition info: status %d, returned %d\n", errno, returned_bytes);

        return FALSE;

    } else {

        //printf("got partition info: offset %I64x, length %I64x\n", PartInfo->StartingOffset, PartInfo->PartitionLength);

    }

   

    return TRUE;

}

BOOL GetPartitionInfo(HANDLE device, PPARTITION_INFORMATION PartInfo)

{

    BOOL status;

    unsigned long returned_bytes;

    //unsigned long returned_bytes, errno;

    status = DeviceIoControl(device,

                             IOCTL_DISK_GET_PARTITION_INFO,

                             NULL,

                             0,

                             PartInfo,

                             sizeof(PARTITION_INFORMATION),

                             &returned_bytes,

                             FALSE);

               

    if (!status) {

        errno = GetLastError();

        //printf("Error getting partition info: status %d, returned %d\n", errno, returned_bytes);

        return FALSE;

    } else {

       //printf("got partition info: offset %I64x, length %I64x\n", PartInfo->StartingOffset, PartInfo->PartitionLength);

    }

   

    return TRUE;

}

ULONG DebugLevel = 1;

                            // 0 = Suppress All Messages

                            // 1 = Display & Fatal Error Message

                            // 2 = Warning & Debug Messages

                            // 3 = Informational Messages

BOOL IsFixedDisk;

WCHAR FoundDevice[256];

BOOL found = FALSE;

VOID DebugPrint( USHORT DebugPrintLevel, PCHAR DebugMessage, ... )

/*++

Routine Description:

    This routine print the given string, if given debug level is <= to the

    current debug level.

Arguments:

    DebugPrintLevel - Debug level of the given message

    DebugMessage - Message to be printed

--*/

{

    va_list args;

    va_start(args, DebugMessage);

    if (DebugPrintLevel <= DebugLevel) {

        char buffer[128];

        (VOID) vsprintf(buffer, DebugMessage, args);

        printf( "%s", buffer );

    }

    va_end(args);

}

/*++

Routine Description:

    This function prints the given Unicode string.

Arguments:

    WCHAR string and length

--*/

void PrintName(PWCHAR Name, USHORT Len)

{

    SHORT i;

    for ( i = 0; i < (Len) ; i++ ) {

        printf("%C", Name[i]);

    }

}

void GetMounts()

{

    DWORD bytesReturned;

    UCHAR Bytes[10000];

    PMOUNTMGR_MOUNT_POINTS pMntPoints = (PMOUNTMGR_MOUNT_POINTS) Bytes;

    MOUNTMGR_MOUNT_POINT mntPoint, *pmnt;

    DWORD err = 0;

    HANDLE h;

    ULONG index;

    WCHAR symbolicName[MAX_PATH], deviceName[MAX_PATH], uniqueId[MAX_PATH];

                h = CreateFile("\\\\.\\MountPointManager",

                                       GENERIC_READ,

                                       FILE_SHARE_READ | FILE_SHARE_WRITE,

                                       NULL,

                                       OPEN_EXISTING,

                                       0,

                                       NULL);

                if (h == INVALID_HANDLE_VALUE) {

                                err = GetLastError();

                                printf("can't open: %d\n", err);

        return;

                }

   

    ZeroMemory(pMntPoints, 10000);

    ZeroMemory(&mntPoint, sizeof(MOUNTMGR_MOUNT_POINT));

   

    pMntPoints->Size = 10000;

    if(DeviceIoControl(h,

                       IOCTL_MOUNTMGR_QUERY_POINTS,

                       &mntPoint,

                       sizeof(MOUNTMGR_MOUNT_POINT),

                       pMntPoints,

                       10000,

                       &bytesReturned,

                       NULL)) {

        if(bytesReturned && pMntPoints->Size && pMntPoints->NumberOfMountPoints) {

            for(index = 0; index < pMntPoints->NumberOfMountPoints; index++) {

                pmnt = &pMntPoints->MountPoints[index];

                ZeroMemory(symbolicName, MAX_PATH);

                ZeroMemory(deviceName, MAX_PATH);

                ZeroMemory(uniqueId, MAX_PATH);

                wcsncpy(symbolicName, (PWCHAR) &Bytes[pmnt->SymbolicLinkNameOffset], pmnt->SymbolicLinkNameLength/sizeof(WCHAR));

                wcsncpy(uniqueId, (PWCHAR) &Bytes[pmnt->UniqueIdOffset], pmnt->UniqueIdLength/sizeof(WCHAR));

                wcsncpy(deviceName, (PWCHAR) &Bytes[pmnt->DeviceNameOffset], pmnt->DeviceNameLength/sizeof(WCHAR));

                //if (IsVolumeGuid(symbolicName, pmnt->SymbolicLinkNameLength/sizeof(WCHAR))) {

                    printf("%d) %ws => %ws\n", index, symbolicName, deviceName);

                //}

                //printf("%d) %ws => %ws\n", index, symbolicName, deviceName);

            }

        }

           

    } else {

        err = GetLastError();

    }

   

    CloseHandle(h);

    printf("err=%d ret=%d\n", err, bytesReturned);

}

int __cdecl main()

/*++

Routine Description:

    This is the main function. It takes no arguments from the user.

Arguments:

    None

Return Value:

  Status

--*/

{

    HDEVINFO hIntDevInfo;

    DWORD index;

    BOOL status;

    //

    // Open the device using device interface registered by the driver

    //

    found = FALSE;

    //

    // Get the interface device information set that contains all devices of event class.

    //

    hIntDevInfo = SetupDiGetClassDevs (

                 (LPGUID) &VolumeClassGuid, //&GUID_DEVCLASS_VOLUMESNAPSHOT, //&MOUNTDEV_MOUNTED_DEVICE_GUID, //

                 NULL, // Enumerator

                 NULL, // Parent Window

                 (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE // Only Devices present & Interface class

                 ));

    if( hIntDevInfo == INVALID_HANDLE_VALUE ) {

        DebugPrint( 1, "SetupDiGetClassDevs failed with error: %d\n", GetLastError() );

        exit(1);

    }

    //

    // Enumerate all the disk devices

    //

    index = 0;

    while (TRUE) {

        status = GetDeviceProperty( hIntDevInfo, index );

        if ( status == FALSE ) {

            break;

        }

        index++;

    }

    SetupDiDestroyDeviceInfoList(hIntDevInfo);

    return 0;

}

#define MAX_COMP_INSTID 2096

#define MAX_COMP_DESC 2096

#define MAX_FRIENDLY 2096

BOOL GetDeviceProperty(HDEVINFO IntDevInfo, DWORD Index )

/*++

Routine Description:

    This routine enumerates the volumes using the Device interface

    GUID VolumeClassGuid. Gets the Adapter & Device property from the port

    driver. Get the mount name, SCSI address and locks the volume for exclusive

    access, if possible.

Arguments:

    IntDevInfo - Handles to the interface device information list

    Index - Device member

Return Value:

  TRUE / FALSE. This decides whether to continue or not

--*/

{

    SP_DEVICE_INTERFACE_DATA interfaceData;

    PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData = NULL;

    STORAGE_PROPERTY_QUERY query;

    PSTORAGE_ADAPTER_DESCRIPTOR adpDesc;

    PSTORAGE_DEVICE_DESCRIPTOR devDesc;

    SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;

    PMOUNTDEV_NAME mountName;

    PSCSI_ADDRESS scsiAddress;

    HANDLE hDevice;

    BOOL status;

    PUCHAR p;

    UCHAR outBuf[BUF_LEN];

    ULONG returnedLength;

    ULONG length = 0,

                                        returned = 0;

    DWORD interfaceDetailDataSize,

                                        reqSize,

                                        errorCode,

                                        i;

    PMOUNTDEV_UNIQUE_ID mountId;

    STORAGE_DEVICE_NUMBER number;

    SP_DEVINFO_DATA deid;

    DWORD dwRegType;

    char szPdoName[MAX_FRIENDLY];

    char buffer[2048];

    //PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX) buffer;

    PDRIVE_LAYOUT_INFORMATION DriveLayout = (PDRIVE_LAYOUT_INFORMATION) buffer;

    PARTITION_INFORMATION PartInfo;

    PARTITION_INFORMATION_EX PartInfoEx;

    interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);

    status = SetupDiEnumDeviceInterfaces (

                IntDevInfo, // Interface Device Info handle

                0, // Device Info data

                (LPGUID)&VolumeClassGuid,

                Index, // Member

                &interfaceData // Device Interface Data

                );

    if ( status == FALSE ) {

        errorCode = GetLastError();

        if ( errorCode == ERROR_NO_MORE_ITEMS ) {

            DebugPrint( 2, "No more interfaces\n" );

        }

        else {

            DebugPrint( 1, "SetupDiEnumDeviceInterfaces failed with error: %d\n", errorCode );

        }

        return FALSE;

    }

       

    //

    // Find out required buffer size, so pass NULL

    //

    status = SetupDiGetDeviceInterfaceDetail (

                IntDevInfo, // Interface Device info handle

                &interfaceData, // Interface data for the event class

                NULL, // Checking for buffer size

                0, // Checking for buffer size

                &reqSize, // Buffer size required to get the detail data

                NULL // Checking for buffer size

                );

    //

    // This call returns ERROR_INSUFFICIENT_BUFFER with reqSize

    // set to the required buffer size. Ignore the above error and

    // pass a bigger buffer to get the detail data

    //

    if ( status == FALSE ) {

        errorCode = GetLastError();

        if ( errorCode != ERROR_INSUFFICIENT_BUFFER ) {

            DebugPrint( 1, "SetupDiGetDeviceInterfaceDetail failed with error: %d\n", errorCode );

            return FALSE;

        }

    }

    //

    // Allocate memory to get the interface detail data

    // This contains the devicepath we need to open the device

    //

    interfaceDetailDataSize = reqSize;

    interfaceDetailData = malloc (interfaceDetailDataSize);

    if ( interfaceDetailData == NULL ) {

        DebugPrint( 1, "Unable to allocate memory to get the interface detail data.\n" );

        return FALSE;

    }

    interfaceDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);

    status = SetupDiGetDeviceInterfaceDetail (

                  IntDevInfo, // Interface Device info handle

                  &interfaceData, // Interface data for the event class

                  interfaceDetailData, // Interface detail data

                  interfaceDetailDataSize, // Interface detail data size

                  &reqSize, // Buffer size required to get the detail data

                  NULL); // Interface device info

    if ( status == FALSE ) {

        DebugPrint( 1, "Error in SetupDiGetDeviceInterfaceDetail failed with error: %d\n", GetLastError() );

        return FALSE;

    }

    //printf("Interface: %s\n", interfaceDetailData->DevicePath);

    memset(szPdoName, 0, MAX_FRIENDLY);

    deid.cbSize = sizeof(SP_DEVINFO_DATA);

    SetupDiEnumDeviceInfo(IntDevInfo, Index, &deid);

    SetupDiGetDeviceRegistryProperty(IntDevInfo, &deid,

                                     SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,

                                     &dwRegType,

                                     (BYTE*) szPdoName,

                                     MAX_FRIENDLY,

                                     NULL);

    //printf(" PdoName : %s\n", szPdoName);

    //

    // Now we have the device path. Open the device interface

    // to send Pass Through command

    hDevice = CreateFile(

                interfaceDetailData->DevicePath, // device interface name

                GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess

                FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode

                NULL, // lpSecurityAttributes

                OPEN_EXISTING, // dwCreationDistribution

                0, // dwFlagsAndAttributes

                NULL // hTemplateFile

                );

               

    if (hDevice == INVALID_HANDLE_VALUE) {

        DebugPrint( 1, "CreateFile failed with error: %d\n", GetLastError() );

        return TRUE;

    }

    free (interfaceDetailData);

    if (hDevice == INVALID_HANDLE_VALUE) {

        DebugPrint( 1, "CreateFile failed with error: %d\n", GetLastError() );

        return TRUE;

    }

    IsFixedDisk = FALSE;

    status = DeviceIoControl(

                    hDevice,

                    IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,

                    &outBuf,

                    BUF_LEN,

                    &outBuf,

                    BUF_LEN,

                    &returnedLength,

                    NULL

                    );

    if ( !status ) {

        DebugPrint( 1, "\nIOCTL_MOUNTDEV_QUERY_DEVICE_NAME failed with error code: %d.\n\n", GetLastError() );

    }

    else {

        mountName = (PMOUNTDEV_NAME)&outBuf;

#if 0

        if (!found) {

            if (wcsstr(mountName->Name, L"Volume\0")) {

                wcsncpy(FoundDevice, mountName->Name, mountName->NameLength);

                //swprintf(FoundDevice, L"%s", mountName->Name);

                found = TRUE;

                printf("\noh yeah we found the device = %ws\n", FoundDevice);

            }

        }

#endif

    }

    // Get Drive letter from mount name

    if (GetStorageDeviceNumber(hDevice, &number)) {

        if (number.PartitionNumber != -1) {

                                GetDriveLetter(mountName);

            printf("Disk #%d, Partition #%d", number.DeviceNumber, number.PartitionNumber);

                    if (GetPartitionInfoEx(hDevice, &PartInfoEx)) {

                printf("\tOffset 0x%I64x\n", PartInfoEx.StartingOffset);

            } else {

                printf("[not available for this device]\n");

            }

        }

    }

    // Close handle the driver

    if ( !CloseHandle(hDevice) ) {

        DebugPrint( 2, "Failed to close device.\n");

    }

    return TRUE;

}

void GetDriveLetter(PMOUNTDEV_NAME mountName)

{

    HANDLE hDevice;

    BOOL status;

    ULONG returnedLength,

                            nameLength,

                            mountPointsSize;

    UCHAR outBuf[BUF_LEN];

    PMOUNTMGR_MOUNT_POINTS mountMgrQueryPoints;

    PMOUNTMGR_MOUNT_POINT pMountPoint;

    USHORT i;

    WCHAR volumeGuid[255];

    BOOL showedDevice;

    PWCHAR pName;

    hDevice = CreateFile(

                MOUNTMGR_NAME, // device interface name

                GENERIC_READ, // dwDesiredAccess

                FILE_SHARE_READ, // dwShareMode

                NULL, // lpSecurityAttributes

                OPEN_EXISTING, // dwCreationDistribution

                0, // dwFlagsAndAttributes

                NULL // hTemplateFile

                );

               

    if (hDevice == INVALID_HANDLE_VALUE) {

        DebugPrint( 1, "CreateFile failed with error: %d\n", GetLastError() );

        return;

    }

    nameLength = mountName->NameLength;

    mountPointsSize = sizeof(MOUNTMGR_MOUNT_POINT) + nameLength;

    pMountPoint = malloc(mountPointsSize);

    ZeroMemory(pMountPoint, mountPointsSize );

    pMountPoint->DeviceNameOffset = (USHORT) sizeof(MOUNTMGR_MOUNT_POINT);

    pMountPoint->DeviceNameLength = (USHORT) nameLength;

    memcpy( pMountPoint + 1, mountName->Name, nameLength );

    ZeroMemory(outBuf, BUF_LEN );

    // Get the triples (symbolic links, mount name & unique ID) from Mount Manager

    status = DeviceIoControl(

                    hDevice,

                    IOCTL_MOUNTMGR_QUERY_POINTS,

                    pMountPoint,

                    mountPointsSize,

                    &outBuf,

                    BUF_LEN,

                    &returnedLength,

                    NULL

                    );

    if ( !status ) {

        DebugPrint( 1, "\nIOCTL_MOUNTMGR_QUERY_POINTS failed with error code: %d.\n\n", GetLastError() );

    }

    mountMgrQueryPoints = (PMOUNTMGR_MOUNT_POINTS) outBuf;

    showedDevice = TRUE;

    for (i = 0; i < mountMgrQueryPoints->NumberOfMountPoints - 1; i++ ) {

        pMountPoint = &mountMgrQueryPoints->MountPoints[i];

        if (!showedDevice) {

            if (pMountPoint->DeviceNameLength) {

                DebugPrint( 1, " Device Name: ");

                PrintName( (PWCHAR)((PCHAR)mountMgrQueryPoints + pMountPoint->DeviceNameOffset), pMountPoint->DeviceNameLength/2);

                printf("\n");

            }

            if (pMountPoint->UniqueIdLength) {

                DebugPrint( 1, " Unique Id: ");

                PrintName( (PWCHAR)((PCHAR)mountMgrQueryPoints + pMountPoint->UniqueIdOffset), pMountPoint->UniqueIdLength/2);

                printf("\n");

            }

            showedDevice = TRUE;

        }

        if (pMountPoint->SymbolicLinkNameLength) {

            //pName = (PWCHAR)((PCHAR)mountMgrQueryPoints + pMountPoint->SymbolicLinkNameOffset);

            //if (wcsstr(pName, L"DosDevices")) {

            // printf("got DosDevices...\n");

            // //PrintName( pName, (pMountPoint->SymbolicLinkNameLength/2));

            // PrintName( (PWCHAR)((PCHAR)mountMgrQueryPoints + pMountPoint->SymbolicLinkNameOffset), (pMountPoint->SymbolicLinkNameLength/2));

            // printf("\n");

            //}

            pName = (PWCHAR)((PCHAR)mountMgrQueryPoints + pMountPoint->SymbolicLinkNameOffset);

            if (wcsstr(pName, L"Volume")) {

                pName = (PWCHAR)((PCHAR)mountMgrQueryPoints + pMountPoint->SymbolicLinkNameOffset);

                pName += 11;

                PrintName( pName, (pMountPoint->SymbolicLinkNameLength/2)-12);

                printf("\t");

            }

            //PrintName( (PWCHAR)((PCHAR)mountMgrQueryPoints + pMountPoint->SymbolicLinkNameOffset), (pMountPoint->SymbolicLinkNameLength/2));

        }

    }

    //

    // Close handle the driver

    if ( !CloseHandle(hDevice) ) {

        DebugPrint( 1, "Failed to close device.\n");

    }

    free(pMountPoint);

    return;

}

/**************************************************mounts.c*************************************************/

/*************************************************MakeFile**************************************************/

#

# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source

# file to this component. This file merely indirects to the real make file

# that is shared by all the driver components of the Windows NT DDK

#

!INCLUDE $(NTMAKEENV)\makefile.def

/*************************************************MakeFile**************************************************/

/*************************************************Sources***************************************************/

TARGETNAME=enumvol

TARGETTYPE=PROGRAM

UMTYPE=console

UMBASE=0x1000000

USE_LIBCMT=1

TARGETPATH=obj

INCLUDES=$(DDK_INC_PATH); \

         $(BASEDIR)\inc; \

         $(BASEDIR)\inc\ddk;

TARGETLIBS= $(DDK_LIB_PATH)\setupapi.lib

SOURCES=mounts.c

/*************************************************Sources**********************************************