How to update file change time from C #?

Files may have a modification date. This date does not match the last modified date or the last access date. The date of change is not displayed through the user interface or .NET API. There are two Win32 GetFileInformationByHandleEx functions for reading and SetFileInformationByHandle for writing a file.

I want to read the change date, add a few hours to it, and write the new date as the file change date.

Now I have the following code:

class Program { static void Main(string[] args) { using (var file = new FileStream(@"c:\path\to\file", FileMode.Open)) { var fileInfo = new FILE_BASIC_INFO(); GetFileInformationByHandleEx( file.Handle, FILE_INFO_BY_HANDLE_CLASS.FileBasicInfo, out fileInfo, (uint)Marshal.SizeOf(fileInfo)); SetFileInformationByHandle( file.Handle, FILE_INFO_BY_HANDLE_CLASS.FileBasicInfo, fileInfo, (uint)Marshal.SizeOf(fileInfo)); } } [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetFileInformationByHandleEx( IntPtr hFile, FILE_INFO_BY_HANDLE_CLASS infoClass, out FILE_BASIC_INFO fileInfo, uint dwBufferSize); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetFileInformationByHandle( IntPtr hFile, FILE_INFO_BY_HANDLE_CLASS infoClass, FILE_BASIC_INFO fileInfo, uint dwBufferSize); private enum FILE_INFO_BY_HANDLE_CLASS { FileBasicInfo = 0 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct FILE_BASIC_INFO { public LARGE_INTEGER CreationTime; public LARGE_INTEGER LastAccessTime; public LARGE_INTEGER LastWriteTime; public LARGE_INTEGER ChangeTime; public uint FileAttributes; } [StructLayout(LayoutKind.Explicit, Size = 8)] private struct LARGE_INTEGER { [FieldOffset(0)] public Int64 QuadPart; [FieldOffset(0)] public UInt32 LowPart; [FieldOffset(4)] public Int32 HighPart; } } 

I can read the change date in this terrible LARGE_INTEGER structure. I want to have a function that can convert this type to System.DateTime and vice versa.

The second problem I am experiencing is that the syntax of the SetFileInformationByHandle method is incorrect. I get PInvokeStackImbalance with this additional information:

Additional Information: The PInvoke function call "Program :: SetFileInformationByHandle" has an unbalanced stack. This is likely due to the fact that the PInvoke managed signature does not match the unmanaged target signature. Verify that the calling agreement and PInvoke signature settings match the target unmanaged signature.

Who can help me?

+1
source share
2 answers

To answer the first part ... How to convert "this awful Large_Interger" to DateTime .. Below is a code snippet.

 using (var file = new System.IO.FileStream(@"sample.log", System.IO.FileMode.Open)) { var fileInfo = new FILE_BASIC_INFO(); GetFileInformationByHandleEx( file.Handle, FILE_INFO_BY_HANDLE_CLASS.FileBasicInfo, out fileInfo, (uint)System.Runtime.InteropServices.Marshal.SizeOf(fileInfo)); var changeTime = DateTime.FromFileTime(fileInfo.ChangeTime.QuadPart); Console.WriteLine(changeTime); System.TimeSpan changedForHowLong = DateTime.Now.Subtract(changeTime); Console.WriteLine(changedForHowLong.Days); } 

I tested the above snippet, it seems to work fine. Let me try to reproduce the problem you encountered with PInvokeStackImbalance ..

Take care

0
source

I found this signature on PInvoke

 [DllImport("Kernel32.dll", SetLastError = true)] private static extern bool SetFileInformationByHandle( IntPtr hFile, int FileInformationClass, IntPtr lpFileInformation, Int32 dwBufferSize); 

Somehow it didn't work. I had to change the parameter type of lpFileInformation to FILE_BASIC_INFO to make it work.

This is a complete C # example called from PowerShell:

 $fu = @" using System; using System.IO; using System.Runtime.InteropServices; public class FileUtility { private struct FILE_BASIC_INFO { [MarshalAs(UnmanagedType.I8)] public Int64 CreationTime; [MarshalAs(UnmanagedType.I8)] public Int64 LastAccessTime; [MarshalAs(UnmanagedType.I8)] public Int64 LastWriteTime; [MarshalAs(UnmanagedType.I8)] public Int64 ChangeTime; [MarshalAs(UnmanagedType.U4)] public UInt32 FileAttributes; } [DllImport("Kernel32.dll", SetLastError = true)] private static extern bool SetFileInformationByHandle( IntPtr hFile, int FileInformationClass, FILE_BASIC_INFO lpFileInformation, Int32 dwBufferSize); public void SetFileChangeTime() { using (FileStream fs = new FileStream(@"c:\path\to\file", FileMode.Open)) { FILE_BASIC_INFO fileInfo = new FILE_BASIC_INFO(); fileInfo.ChangeTime = 943044610000000; SetFileInformationByHandle( fs.Handle, 0, // the same as FILE_INFO_BY_HANDLE_CLASS.FileBasicInfo fileInfo, Marshal.SizeOf(fileInfo)); } } } "@ Add-Type -TypeDefinition $fu -IgnoreWarnings $f = New-Object -TypeName FileUtility $f.SetFileChangeTime() 

I ran an example with other date properties, as they are shown in Explorer, and it worked.

Edit

This code does not run in debug mode in VS. As mentioned above, this is an exception. Running EXE on the command line does not raise an exception. But the date of change is not updated. However, it only works in PowerShell. It’s strange.

0
source

Source: https://habr.com/ru/post/1492613/


All Articles