I saw a pinvoke signature that passed a UInt64 instead of a FILETIME, what’s up with that?
A customer had a question about a pinvoke signature that used a
UInt64 to hold a
[DllImport("kernel32.dll", SetLastError = true) static external bool GetProcessTimes( IntPtr hProcess, out UInt64 creationTime, out UInt64 exitTime, out UInt64 kernelTime, out UInt64 userTime);
Is this legal? The documentation for
Do not cast a pointer to a FILETIME structure to either a ULARGE_INTEGER* or __int64* value because it can cause alignment faults on 64-bit Windows.
Are we guilty of this cast in the above code? After all you can’t treat a
There are two types of casts possible in this scenario.
- Casting from
- Casting from
FILETIME structure requires 4-byte alignment, and the
__int64 data type requires 8-byte alignment. Therefore the first cast is unsafe, because you are casting from a pointer with lax alignment requirements to one with stricter requirements. The second cast is safe because you are casting from a pointer with strict alignment requirements to one with laxer requirements.
Everything in the blue box is also in the pink box, but not vice versa.
Which cast is the one occurring in the above pinvoke signature?
In the above signature, the
UInt64 is being allocated by the interop code, and therefore it is naturally aligned for
UInt64, which means that it is 8-byte aligned. The
GetProcessTimes function then treats those eight bytes as a
FILETIME. So we are in the second case, where we cast from
Mind you, you can avoid all this worrying by simply declaring your pinvoke more accurately. The correct solution is to declare the last four parameters as
ComTypes.FILETIME. Now there are no sneaky games. Everything is exactly what it says it is.
Bonus reading: The article Use PowerShell to access registry last-modified time stamp shows how to use the
ComTypes.FILETIME technique from PowerShell.