Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GetShortPathNameA not working in C#

I'm trying to get get the short filename from a long filename but I'm having problem in c# code. VB.Net code is:

Declare Function GetShortPathName Lib "kernel32" _
    Alias "GetShortPathNameA" (ByVal lpszLongPath As String, _
    ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long

Public Function GetShortName(ByVal sLongFileName As String) As String
    Dim lRetVal As Long, sShortPathName As String, iLen As Integer
    'Set up buffer area for API function call return
    sShortPathName = Space(255)
    iLen = Len(sShortPathName)

    'Call the function
    lRetVal = GetShortPathName(sLongFileName, sShortPathName, iLen)
    'Strip away unwanted characters.
     GetShortName = Left(sShortPathName, lRetVal)
End Function

I've converted this function to c#:

[DllImport("kernel32", EntryPoint = "GetShortPathNameA")]
static extern long GetShortPathName(string lpszLongPath, string lpszShortPath, long cchBuffer);

public string GetShortName(string sLongFileName)
{
    long lRetVal;
    string sShortPathName;
    int iLen;

    // Set up buffer area for API function call return
    sShortPathName = new String(' ', 1024);
    iLen = sShortPathName.Length;

    // Call the function
    lRetVal = GetShortPathName(sLongFileName, sShortPathName, iLen);

    // Strip away unwanted characters.
    return sShortPathName.Trim();
}

But I cant get the c# version work. Am I missing something or what is wrong?

like image 673
HasanG Avatar asked Dec 30 '25 19:12

HasanG


2 Answers

The VB declaration dates back to VB6, it is quite inappropriate for a .NET language. Although the P/Invoke marshaller will allow unmanaged code scribbling into a string, it causes random failure due to string interning. You also really want to use the Unicode version so you don't get unexpected character translation. And you want to do something meaningful if the function fails. Here's my version:

public static string GetShortName(string sLongFileName) {
  var buffer = new StringBuilder(259);
  int len = GetShortPathName(sLongFileName, buffer, buffer.Capacity);
  if (len == 0) throw new System.ComponentModel.Win32Exception();
  return buffer.ToString();
}

[DllImport("kernel32", EntryPoint = "GetShortPathName", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetShortPathName(string longPath, StringBuilder shortPath, int bufSize);
like image 192
Hans Passant Avatar answered Jan 01 '26 09:01

Hans Passant


Maybe because of CharSet/Marshaling, remember also that string are imutable. Try the following :

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
static extern uint GetShortPathName(
   [MarshalAs(UnmanagedType.LPTStr)]
   string lpszLongPath,
   [MarshalAs(UnmanagedType.LPTStr)]
   StringBuilder lpszShortPath,
   uint cchBuffer);

(From pinvoke)

/// <summary>
/// The ToLongPathNameToShortPathName function retrieves the short path form of a specified long input path
/// </summary>
/// <param name="longName">The long name path</param>
/// <returns>A short name path string</returns>
public static string ToShortPathName(string longName)
{
    uint bufferSize = 256;

    // don´t allocate stringbuilder here but outside of the function for fast access
    StringBuilder shortNameBuffer = new StringBuilder((int)bufferSize);

    uint result = GetShortPathName(longName, shortNameBuffer, bufferSize);

    return shortNameBuffer.ToString();
}
like image 37
Guillaume Avatar answered Jan 01 '26 09:01

Guillaume



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!