Search
Module:
Directory

   Desktop Functions:

   Smart Device Functions:


Show Recent Changes
Subscribe (RSS)
Misc. Pages
Comments
FAQ
Helpful Tools
Playground
Suggested Reading
Website TODO List
Download Visual Studio Add-In

GetVolumePathNamesForVolumeName (kernel32)
 
.
Summary
Retrieves a list of path names for the specified volume name.

C# Signature:

[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetVolumePathNamesForVolumeNameW(string lpszVolumeName,
        char [] lpszVolumePathNames, uint cchBuferLength,
        ref UInt32 lpcchReturnLength);

C# Signature 2:

[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetVolumePathNamesForVolumeNameW(
        [MarshalAs(UnmanagedType.LPWStr)]
        string lpszVolumeName,
        [MarshalAs(UnmanagedType.LPWStr)]
        string lpszVolumePathNames,
        uint cchBuferLength,
        ref UInt32 lpcchReturnLength);

C# Signature 3:

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetVolumePathNamesForVolumeName(string lpszVolumeName, char[] lpszVolumePathNames, uint cchBuferLength, out UInt32 lpcchReturnLength);

VB Signature:

Declare Function GetVolumePathNamesForVolumeName Lib "kernel32.dll" (TODO) As TODO

VB Signature #2:

Imports System.Runtime.InteropServices

Partial Public Class Win32Methods

'''Return Type: BOOL->int
'''param0: LPCTSTR->LPCWSTR->WCHAR*
'''param1: LPTSTR->LPWSTR->WCHAR*
'''param2: DWORD->unsigned int
'''param3: PDWORD->DWORD*
  <DllImportAttribute("kernel32.dll", _
    SetLastError:=True, _
    EntryPoint:="GetVolumePathNamesForVolumeNameW")> _
  Public Shared Function GetVolumePathNamesForVolumeNameW(
                               <[In]()> <MarshalAs(UnmanagedType.LPTStr)>
                                ByVal sVolumeName As String, _
                                <MarshalAs(UnmanagedType.LPWStr)> _
                                ByVal lpBuffer As IntPtr, _
                                ByVal uintBufferLen As UInteger, _
                                <Out()> ByRef uintReturnLen As UInteger) _
                             As <MarshalAs(UnmanagedType.Bool)> Boolean
  End Function

End Class

User-Defined Types:

None.

Alternative Managed API:

Do you know one? Please contribute it!

Notes:

The VB Code was generated by the tool at http://clrinterop.codeplex.com/releases/view/14120. I believe this to be the same tool referenced at http://blogs.msdn.com/b/vbteam/archive/2008/03/14/making-pinvoke-easy.aspx. The StringBuilder limitation appears to apply to this code as well, and it will only return the first path/mountpoint found, but the method does work inside that limitation. I will post updated code as soon as I code and test.

Updated: VB code now uses IntPtr instead of StringBuilder - see sample below

Using StringBuilder for the buffer does not work since this function returns the names as a bunch of strings separated by the null character ('\0'). So StringBuilder would only report the first item. Therefore we store it in a char array, which can later be converted to a bunch of strings.

S.M.
The first C# signature would not work for me. I would get an ERROR_INVALID_PARAMETER error. The second signature works with the second example below.

Tips & Tricks:

Please add some!

Sample Code:

        UInt32 dwRequired = 0;

        char[] buffer = new char[260];

        if (!GetVolumePathNamesForVolumeName(volumeName, buffer, (uint)buffer.Length, ref dwRequired))
        {
        // Not enough room in buffer perhaps? Try a bigger one
        buffer = new char[dwRequired];
        if (!GetVolumePathNamesForVolumeName(volumeName, buffer, (uint)buffer.Length, ref dwRequired))
            throw new Win32Exception();
        }

Sample Code 2:

    public List<string> GetMountPointsForVolume(string volumeDeviceName)
    {
        List<string> result = new List<string>();

        // GetVolumePathNamesForVolumeName is only available on Windows XP/2003 and above
        int osVersionMajor = Environment.OSVersion.Version.Major;
        int osVersionMinor = Environment.OSVersion.Version.Minor;
        if (osVersionMajor < 5 || (osVersionMajor == 5 && osVersionMinor < 1))
        {
        return result;
        }

        try
        {
        uint lpcchReturnLength = 0;
        string buffer = "";

        GetVolumePathNamesForVolumeNameW(volumeDeviceName, buffer, (uint)buffer.Length, ref lpcchReturnLength);
        if (lpcchReturnLength == 0)
        {
            return result;
        }

        buffer = new string(new char[lpcchReturnLength]);

        if (!GetVolumePathNamesForVolumeNameW(volumeDeviceName, buffer, lpcchReturnLength, ref lpcchReturnLength))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        string[] mounts = buffer.Split('\0');
        foreach (string mount in mounts)
        {
            if (mount.Length > 0)
            {
            result.Add(mount);
            }
        }
        }
        catch (Exception ex)
        {
        Console.WriteLine(ex.ToString());
        }

        return result;
    }

Sample VB.Net Code (.Net Framework 3.5sp1)

  Imports System.Runtime.InteropServices
  Private Sub ListMountPoints(Optional strVolumeName As String = "")
    ' if no Volume GUID passed to sub, use this one (corresponds to my USB stick)
    If strVolumeName = "" Then
        strVolumeName = "\\?\Volume{9a615499-414c-11e0-bd72-78e7d1722cbc}\"
    End If
    ' make this a static in order to stop race condition/thread lock - suspect garbage collector
    Static lpBuffer As IntPtr = Marshal.AllocHGlobal(1)
    Dim uintBufferLen As UInteger = 0, uintBuffReqLen As UInteger = 0
    Const ERROR_MORE_DATA = 234, ERROR_FILE_NOT_FOUND = 2
    Dim retval As Boolean = False

  Module Module1
    Partial Public Class PInvoke
    Try
        ' call function to get Required Buffer Length first
        retval = Win32Methods.GetMountPointsIntPtr(strVolumeName, lpBuffer, uintBufferLen, uintBuffReqLen)
        If Not retval Then
        Dim errVal As Integer = Marshal.GetLastWin32Error()
        If errVal = ERROR_MORE_DATA Then
            'MsgBox("The last Win32 error was: ERROR_MORE_DATA")
        ElseIf errVal = ERROR_FILE_NOT_FOUND Then
            MsgBox("File not found, did you remember to plug in the USB drive?")
            Exit Sub
        Else
            MsgBox("Error! The last Win32 error was: " + CStr(errVal))
        End If
        End If
        ' now set the buffer length
        uintBufferLen = uintBuffReqLen
        'zero out the length indicator
        uintBuffReqLen = 0

    ' Have to use Pointer to return pathnames, StringBuilder only returns first NULL-terminated stgring
    <DllImportAttribute("kernel32.dll", _
                CharSet:=CharSet.Unicode, _
                EntryPoint:="GetVolumePathNamesForVolumeNameW", _
                SetLastError:=True)>
    Public Shared Function GetMountPointsPtr(ByVal sVolumeName As String, _
                            ByVal lpBuffer As IntPtr, _
                            ByVal uintBufferLen As UInteger, _
                            ByRef uintReturnLen As UInteger) _
                        As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    End Class
    Catch ex As Exception
        Dim errVal As Integer = Runtime.InteropServices.Marshal.GetLastWin32Error()
        MsgBox(ex.Message + ". The last Win32 error was: " + CStr(errVal))
    End Try

    Sub Main()
    ListMountPoints()
    End Sub

    ' if no Volume GUID passed to sub, use the one corresponding to my USB stick
    Private Sub ListMountPoints(Optional strVolumeName As String = "\\?\Volume{9a615499-414c-11e0-bd72-78e7d1722cbc}\")

    ' now call the function again with the right buffer length
    lpBuffer = Runtime.InteropServices.Marshal.ReAllocHGlobal(lpBuffer, CType(uintBuffReqLen, IntPtr))
    ' uintBufferLen = uintBuffReqLen
    uintBuffReqLen = 0
    Try
        Dim uintBufferLen As UInteger = CUInt((IntPtr.Size) / 2)
        Dim uintRequiredBufferLen As UInteger = 0
        Dim Win32ErrVal As Integer = 0
        Dim lpBuffer As IntPtr = Marshal.AllocHGlobal(IntPtr.Size)

        ' call function to get Required Buffer Length first
        PInvoke.GetMountPointsPtr(strVolumeName, lpBuffer, uintBufferLen, uintRequiredBufferLen)

        Win32ErrVal = Marshal.GetLastWin32Error()
        If Win32ErrVal = 234 Then
        'expected return value (ERROR_MORE_DATA), as our initial buffer is not large enough
        ElseIf Win32ErrVal = 2 Then
        ' oops
        Throw New ApplicationException("Invalid volume specified?")
        Else
        Throw New ApplicationException("Exception getting required buffer size.")
        If CBool(Not (Win32Methods.GetMountPointsIntPtr(strVolumeName, lpBuffer, uintBufferLen, uintBuffReqLen))) Then
        Dim errVal As Integer = Runtime.InteropServices.Marshal.GetLastWin32Error()
        MsgBox("The last Win32 error was: " + CStr(errVal))
        End If
    Catch ex As Exception
        Dim errVal As Integer = Runtime.InteropServices.Marshal.GetLastWin32Error()
        MsgBox(ex.Message + ". The last Win32 error was: " + CStr(errVal))
    End Try

        ' reallocate the IntPtr with the right size
        lpBuffer = Marshal.ReAllocHGlobal(lpBuffer, CType(uintRequiredBufferLen * 2, IntPtr))
        ' now set the buffer length
        uintBufferLen = uintRequiredBufferLen
        'zero out the length indicator
        uintRequiredBufferLen = 0
        ' reset errVal
        Win32ErrVal = 0
    Dim strOutput As String = Runtime.InteropServices.Marshal.PtrToStringUni(lpBuffer, CInt(uintBuffReqLen))
    Dim tmp As Integer = InStr(strOutput, vbNullChar)
    strOutput = Strings.Replace(strOutput, vbNullChar, vbCrLf, , , vbBinaryCompare)
    ' Free the buffer.
    Runtime.InteropServices.Marshal.FreeHGlobal(lpBuffer)
    lpBuffer = IntPtr.Zero
    MsgBox(strVolumeName + vbCrLf + " has the following mountpoints: " + vbCrLf + strOutput.ToString)

        If CBool(Not (PInvoke.GetMountPointsPtr(strVolumeName, lpBuffer, _
                            uintBufferLen, uintRequiredBufferLen))) Then
        Throw New ApplicationException("Exception Occured @ line 54!")
        End If

        ' retrieve the mountpoints(s)
        Dim strOutput As String = Marshal.PtrToStringUni(lpBuffer, CInt(uintRequiredBufferLen))

        If Not (CBool(lpBuffer = IntPtr.Zero)) Then
        Marshal.FreeHGlobal(lpBuffer)
        lpBuffer = IntPtr.Zero
        End If

        Console.WriteLine(strVolumeName + " has the following mountpoints: " _
                  + vbCrLf + strOutput.ToString)

    Catch ex As Exception
        Dim errVal As Integer = Marshal.GetLastWin32Error()
        Console.WriteLine(ex.Message + " The last Win32 error was: " + CStr(errVal))
    End Try
    End Sub
  End Module
  End Sub

Documentation

Please edit this page!

Do you have...

  • helpful tips or sample code to share for using this API in managed code?
  • corrections to the existing content?
  • variations of the signature you want to share?
  • additional languages you want to include?

Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).

 
Access PInvoke.net directly from VS:
Terms of Use
Edit This Page
Find References
Show Printable Version
Revisions