getvolumepathnamesforvolumename (kernel32)
Last changed: -80.254.169.201

.
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

  Module Module1
    Partial Public Class PInvoke

    ' 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

    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}\")

    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.")
        End If

        ' 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

        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

Documentation