dotnet / dotnet-api-docs

.NET API reference documentation (.NET 5+, .NET Core, .NET Framework)
https://docs.microsoft.com/dotnet/api/
Other
720 stars 1.56k forks source link

So..the C# conversion routines that says "FromFileTime" doesn't actually work with a FILETIME #968

Open PeterSmithRedmond opened 6 years ago

PeterSmithRedmond commented 6 years ago

There's a C++ FILETIME construct in Windows. What I was actually looking for was a way to convert that sort of structure into a nice C# version. Instead I get something that would work, if only I could convert a FILETIME into a 64-bit long. Which I can't.


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

AikenBM commented 5 years ago

Why can't you convert a FILETIME into a 64-bit long?

The WinAPI seems to think you should need to do that to work with it. If you look at the FILETIME documentation, it says:

It is not recommended that you add and subtract values from the FILETIME structure to obtain relative times. Instead, you should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member, and copy the LowPart and HighPart members into the FILETIME structure.

There's even a fairly detailed KB article for working with FILETIMEs where they do exactly that.

So, for at least some operations, C++ tells you to convert the FILETIME to an unsigned 64-bit integer. Why not do that in C#? Something like this should work regardless of processor endianness:

long ft = (long)((ulong)HighPart * (ulong)0x100000000 + (ulong)LowPart);
DateTime dt = new DateTime(ft);

Note that DateTime.MaxValue.Ticks is about a third what Int64.MaxValue is, and DateTime.MinValue.Ticks is 0, so we implicitly can't handle negative tick values or values outside the range of a signed 64-bit integer. If you run into a problem casting converting the unsigned 64-bit integer, you weren't going to be able to interpret it as a DateTime anyways. Similarly, if you look at the C++ FileTimeToSystemTime method, that also doesn't work on any value that would be larger than a signed 64-bit integer.

I mean, I understand that you want to easily pass parameters from C++ to a C# method, but in my experience, systems that output Windows filetimes (including WMI, Active Directory, and other C# methods like DateTime.ToFileTime()) almost always return either a 64-bit integer or a string representation of a 64-bit integer. The WinAPI doesn't because a lot of the WinAPI is still based in the 16-bit era. That's why ULARGE_INTEGER's property is a QuadPart. It used to be a quadruple word.