В WinAPI есть такие функции как FindFirstFile и FindNextFile, которые используют структуру WIN32_FIND_DATA, для .NET, Микрософт определяет её в виде класса:
[Serializable, StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto), BestFitMapping(false)]
internal class WIN32_FIND_DATA
{
internal int dwFileAttributes;
internal int ftCreationTime_dwLowDateTime;
internal int ftCreationTime_dwHighDateTime;
internal int ftLastAccessTime_dwLowDateTime;
internal int ftLastAccessTime_dwHighDateTime;
internal int ftLastWriteTime_dwLowDateTime;
internal int ftLastWriteTime_dwHighDateTime;
internal int nFileSizeHigh;
internal int nFileSizeLow;
internal int dwReserved0;
internal int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
internal string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=14)]
internal string cAlternateFileName;
public WIN32_FIND_DATA();
}
Я его чуть переделал, и расчета того что ftCreationTime_dwLowDateTime и ftCreationTime_dwHighDateTime располагаются как раз в таком порядке, что если их накрыть long-полем, то оно получит валидное значение:
[Serializable]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
[BestFitMapping(false)]
class WIN32_FIND_DATA
{
public int dwFileAttributes;
//public int ftCreationTime_dwLowDateTime;
//public int ftCreationTime_dwHighDateTime;public long CreationTime;
public int ftLastAccessTime_dwLowDateTime;
public int ftLastAccessTime_dwHighDateTime;
public int ftLastWriteTime_dwLowDateTime;
public int ftLastWriteTime_dwHighDateTime;
public int nFileSizeHigh;
public int nFileSizeLow;
int Reserved0;
int Reserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string FileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string AlternateFileName;
}
но не тут то было, DateTime.FromFileTime() вылетает с руганью на неверное значение параметра. Тогда я поменял в long-поле первое слово и второе местами:
и, о чудо, оно зароботало. Но появилась другая проблема. FileName сдвинулось на одно слово (4 байта) так, как будто я добавил лишнее intовое поле (пример: fileData.FileName вместо "Yahoo!" теперь содержит "hoo!").
Вопрос не жизненно важный, я проблему решил оставив структуру в прежнем виде
public static DateTime FileTimeToDateTime(int highWord, int lowWord)
{
return DateTime.FromFileTime((((long)highWord) << 32) + lowWord);
}
Интересно почему при замене двух Int32 на одно Int64 поля сдвинулись, и почему Int64 ведет себя так, как будто слова в нем располагаются в big-endian порядке т.е. сначала старшее слово потом младшее, а не так как принято на x86 платформе?
Здравствуйте, adontz, Вы писали: A>Microsoft не имеет отношения к определению выше. Смотри Си хедеры и всё встанет на свои места.
Вы видели первый вариант класса? Я его выдернул рефлектором, и то как у них там все устроено — все работает, второй вариант — это подправленный мной, по моему мнению должен был работать тоже, но нет. К тому же я получил неожиданный результат и задал вопрос: почему так?
Хорошо, смотрим Си хедеры:
О том что FILETIME сруктура из двух 32битных полей, а не одно 64битное и порядов этих 32битных полей фиксирован и абсолютно никак не связан со способом представления 64битного числа. То что кому-то вдруг захотелось вместо FILETIME использовать long это его личная пробелма и замена не является корректной.
Здравствуйте, adontz, Вы писали: A>О том что FILETIME сруктура из двух 32битных полей, а не одно 64битное и порядов этих 32битных полей фиксирован и абсолютно никак не связан со способом представления 64битного числа. То что кому-то вдруг захотелось вместо FILETIME использовать long это его личная пробелма и замена не является корректной.
Так вот это я и пытаюсь понять, почему некорректна? Перое 32битное поле является младшей частью, второе — старшей, 4байта+4байта=8байт=64бит размер подходит, расположение тоже, так в чем проблема? У long'a на x86 архитектуре сначала идут младшие 32 бит замем старшие 32 бит, и под .NET long имеет размер 64 бита.
Здравствуйте, Shadedsun, Вы писали:
S>Так вот это я и пытаюсь понять, почему некорректна? Перое 32битное поле является младшей частью, второе — старшей, 4байта+4байта=8байт=64бит размер подходит, расположение тоже, так в чем проблема? У long'a на x86 архитектуре сначала идут младшие 32 бит замем старшие 32 бит, и под .NET long имеет размер 64 бита.
Здравствуйте, Shadedsun, Вы писали:
S>Интересно почему при замене двух Int32 на одно Int64 поля сдвинулись, и почему Int64 ведет себя так, как будто слова в нем располагаются в big-endian порядке т.е. сначала старшее слово потом младшее, а не так как принято на x86 платформе?
Я думаю, когда вы попытались накрыть ftCreationTime_dwLowDateTime и ftCreationTime_dwHighDateTime одним 64-битным интом, этот инт из-за выравнивания сдвинулся еще на 32 бита, и накрыл собой ftLastAccessTime_dwHighDateTime и ftLastWriteTime_dwLowDateTime. Результат выглядел как валидное время с перепутанными младшей и старшей половинками, но на самом деле младшая и старшая половинки были взяты из 2-х разных времен. Это же соображение объясняет и тот факт, что FileName тоже сдвинулось на 4 байта (т.е., 32 бита).
Здравствуйте, Pzz, Вы писали: Pzz>Я думаю, когда вы попытались накрыть ftCreationTime_dwLowDateTime и ftCreationTime_dwHighDateTime одним 64-битным интом, этот инт из-за выравнивания сдвинулся еще на 32 бита, и накрыл собой ftLastAccessTime_dwHighDateTime и ftLastWriteTime_dwLowDateTime. Результат выглядел как валидное время с перепутанными младшей и старшей половинками, но на самом деле младшая и старшая половинки были взяты из 2-х разных времен. Это же соображение объясняет и тот факт, что FileName тоже сдвинулось на 4 байта (т.е., 32 бита).
Браво, в точку. [StructLayout(LayoutKind.Sequential, Pack=1, CharSet = CharSet.Unicode)] и все стало на свои места.
Умница Pzz.