GetShortPathNameA не работает в C #

2

Я пытаюсь получить короткое имя файла из длинного имени файла, но у меня проблема с кодом С#. Код 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

Я преобразовал эту функцию в С#:

[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();
}

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

Теги:
winapi

3 ответа

6
Лучший ответ

Объявление 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

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

[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();
}
3

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();
}
  • 0
    В Windows 10 iLen должен быть uint, за исключением того, что: Большое спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню