GetShortPathNameA не работает в C # - PullRequest
2 голосов
/ 06 апреля 2010

Я пытаюсь получить короткое имя файла из длинного имени файла, но у меня проблема в коде c #. VB.Net код:

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

Я преобразовал эту функцию в 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();
}

Но я не могу заставить работать версию c #. Я что-то упустил или что-то не так?

Ответы [ 3 ]

6 голосов
/ 06 апреля 2010

Объявление VB восходит к VB6, оно совершенно не подходит для языка .NET. Хотя маршаллер P / Invoke разрешает неуправляемый код в строке, это вызывает случайный сбой из-за интернирования строк. Вы также действительно хотите использовать версию Unicode, чтобы не получить неожиданный перевод символов. И вы хотите сделать что-то значимое, если функция не работает. Вот моя версия:

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);
3 голосов
/ 06 апреля 2010

pinvoke.net перечисляет импорт в таких:

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

pinvoke.net - отличный справочник для подобных проблем, когда вы не совсем уверены, как будет звучать единственное число.

Это изменило бы ваш код следующим образом:

public static string GetShortName(string sLongFileName)
{
    long lRetVal;
    int iLen = 1024;
    StringBuilder sShortPathName = new StringBuilder(iLen);

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

    // Strip away unwanted characters.
    return sShortPathName.ToString();
}
3 голосов
/ 06 апреля 2010

Может быть, из-за CharSet / Marshaling, помните также, что строки являются неизменяемыми. Попробуйте следующее:

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

(от 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();
}
...