3

尝试从我的 C# 程序中 P/InvokeSetFileTime函数,我使用以下签名:

[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);

该文档说明了以下非托管签名:

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

它对第二、第三和第四个参数说它们可以是可选的:

如果应用程序不需要更改此信息,则此参数可以为 NULL。

这正是我想要做的:只传递三个日期时间值之一,并将其​​他设置为null.

我完全不知道如何用 P/Invoke 签名来表达这一点。

因此我的问题是:

哪个是能够传递nullSetFileTime函数参数的正确 P/Invoke 签名(或正确的调用方式)?

编辑1:

由于FileInfo该类已经提供了用于设置文件时间的可写属性,您可能会问,为什么我要自己做而不是使用该类。

原因是我打算在我的Long Paths库中使用这个函数来克服MAX_PATH限制,因此不能使用标准的 .NET 函数。

因此FileInfo,不幸的是,使用该类不是一种选择。

编辑2:

我已经通过使用 Hans 建议的解决方案解决了这个问题。之后,我在函数下方发现了一条用户提供的评论

此外,为其中一个参数指定零值与指定 NULL 具有相同的效果。

虽然我没有检查这是否属实,但对于与我有类似要求的其他人来说,它可能仍然是一个选择。

4

1 回答 1

3

您无法使用 C# 中的ref关键字对其进行建模,该关键字始终在运行时生成非空指针。您实际上必须声明它long*,这需要使用 unsafe 关键字。&local-var使用语法传递参数或使用null.

避免使用不安全的一个可能技巧是使用不同名称声明此方法的 3 个版本,使用 DllImport 的 EntryPoint 属性将它们全部映射到 SetFileTime()。指定您不想设置为 IntPtr 的那些,以便您可以传递 IntPtr.Zero,即您想要设置为 ref long 的那个。例如:

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

对 SetFileAccessTime 和 SetFileWriteTime 重复此操作。

于 2012-07-04T13:34:58.977 回答