3

Trying to P/Invoke the SetFileTime function from my C# program, I am using the following signature:

[DllImport(@"kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetFileTime(
    IntPtr hFile,
    ref long lpCreationTime,
    ref long lpLastAccessTime,
    ref long lpLastWriteTime);

The documentation states the following unmanaged signature:

BOOL WINAPI SetFileTime(
  __in      HANDLE hFile,
  __in_opt  const FILETIME *lpCreationTime,
  __in_opt  const FILETIME *lpLastAccessTime,
  __in_opt  const FILETIME *lpLastWriteTime
);

It says for the 2nd, 3rd and 4th parameter that they can be optional:

This parameter can be NULL if the application does not need to change this information.

And this is exactly what I want to do: Pass only one of the three date time values and have the others set to null.

I'm completely lost on how to express this in terms of P/Invoke signature.

Therefore my question is:

Which is the correct P/Invoke signature (or the correct way of calling) to be able to pass null to the SetFileTime function parameters?

Edit 1:

Since the FileInfo class already provides a writable property for setting the file times, you may ask, why I'm doing it on my own instead of using the class.

The reason is that I'm planning to use this function in my Long Paths library which is used to overcome the MAX_PATH limit and therefore cannot use the standard .NET functions.

Therefore using the FileInfo class is not an option, unfortunately.

Edit 2:

I've solved it by using the solution suggested by Hans. After that, I found a user-contributed comment below the function that says:

In addition, specifying a zero value for one of the parameters has the same effect as specifying NULL.

Although I did not check whether this is true, it might still be an option for others having a similar requirement to mine.

River
  • 8,585
  • 14
  • 54
  • 67
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • 3
    You can use IntPtr but...why P/Invoke?! Why not System.IO.FileInfo? Those properties are R/W. It can be done in C# without any call to native API. – Adriano Repetti Jul 04 '12 at 13:22
  • Thanks, @Adriano good point regarding the `FileInfo` class :-). Actually I'm planning to use this function in my [Long Paths](http://zetalongpaths.codeplex.com) library which is used to overcome the `MAX_PATH` limit and therefore cannot use the standard .NET functions. – Uwe Keim Jul 04 '12 at 13:32

1 Answers1

4

You cannot model that with the ref keyword in C#, that always produces a non-null pointer at runtime. You'll actually have to declare it long*, which requires using the unsafe keyword. Pass the argument with the &local-var syntax or use null.

One possible trick to avoid using unsafe is to declare 3 versions of this method with different names, using the DllImport's EntryPoint property to map them all to SetFileTime(). Specifying the ones you don't want to set as IntPtr so you can pass IntPtr.Zero, the one you do want to set as ref long. For example:

[DllImport("kernel32.dll", SetLastError = true, EntryPoint="SetFileTime", ExactSpelling=true)]
internal static extern bool SetFileCreateTime(
    IntPtr hFile,
    ref long lpCreationTime,
    IntPtr lpLastAccessTimeUnused,
    IntPtr lpLastWriteTimeUnused);

Repeat for SetFileAccessTime and SetFileWriteTime.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks, Hans, I've updated my question with the reason why I think that I cannot use the standard .NET file I/O classes. – Uwe Keim Jul 04 '12 at 13:36