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**********************************************
Comments
- Anonymous
January 07, 2014
There's a memory corruption error in the GetDrive function. fee is called on a pointer that didn't come from the heap. Near the top: pMountPoint = malloc(mountPointsSize); Later, the loop for (i = 0; i < mountMgrQueryPoints->NumberOfMountPoints - 1; i++ ) contains: pMountPoint = &mountMgrQueryPoints->MountPoints[i]; thereby bashing the original pMountPoint then right before the return, fee is called: free(pMountPoint); but that's no longer the pMountPoint we got from malloc. I simply changed the pMountPoint assignment within the loop to be: PMOUNTMGR_MOUNT_POINT pMountPoint = &mountMgrQueryPoints->MountPoints[i]; so it's a locally scoped pMountPoint and doesn't bash the one that came from malloc.