C#winApi-获取注册表的最后写入日期

本文关键字:日期 最后 获取 注册表 C#winApi- | 更新日期: 2023-09-27 18:21:58

我的目标是获取某个寄存器的最后一次写入时间。使用获取寄存器im的值

RegistryKey mKey;
//...
mKey.GetValue("SomeRegName");

这很好,因为mKey的一切都设置得很好。我发现我需要用这个来获得最后一次写作时间:

[DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    extern private static int RegQueryInfoKey(
        UIntPtr hkey,
        out StringBuilder lpClass,
        ref uint lpcbClass,
        IntPtr lpReserved,
        out uint lpcSubKeys,
        out uint lpcbMaxSubKeyLen,
        out uint lpcbMaxClassLen,
        out uint lpcValues,
        out uint lpcbMaxValueNameLen,
        out uint lpcbMaxValueLen,
        out uint lpcbSecurityDescriptor,
        IntPtr lpftLastWriteTime);

所以我需要一个钥匙的把手,但我不能这样做:

UIntPtr hkey = new UIntPtr(mKey.Handle);
UIntPtr hkey = (UIntPtr)mKey.Handle;

因为SafeRegistryHandle无法转换为UIntPtr。我的问题是我应该如何调用这个winapi函数来获得我需要的东西?第二个问题是如何将IntPtr lpftLastWriteTime转换为DateTime

C#winApi-获取注册表的最后写入日期

RegQueryInfoKey的声明中替换

UIntPtr hkey

带有

SafeRegistryHandle handle

并通过CCD_ 7。

至于文件时间,不要将其作为IntPtr传递。而是使用FILETIME结构。

[StructLayout(LayoutKind.Sequential)]
public struct FILETIME {
    public uint DateTimeLow;
    public uint DateTimeHigh;
}

并像这样声明参数:

out FILETIME lpftLastWriteTime

或者,正如Hans有益的评论,使用long

out long lpftLastWriteTime

然后可以直接传递给

DateTime.FromFileTimeUtc()

其他一些评论:

  • 注册表函数不调用SetLastError
  • 设置EntryPoint有点毫无意义
  • 第二个参数应该是StringBuilder lpClass

我想你已经从pinvoke.net的声明开始了。遗憾的是,这些声明的质量往往很差。

下面是一个完整的实现:

MSDN帮助链接:

基本MSDN链接-https://msdn.microsoft.com/en-us/library/ms724284(v=vs.85).aspx

更改基本链接中的msXXXXX编号。

  1. ms724284-FILETIME结构
  2. ms724897-RegOpenKeyEx
  3. ms724837-RegCloseKey
  4. ms724902-RegQueryInfoKey
  5. ms724205-"转换FILETIME的其他方法-将文件时间更改为当前时间"

守则:

代码包括WinAPI方法签名(来自PInvoke.net)

using System;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;
using Microsoft.Win32;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
namespace RegistryUtils
{
    public static class RegistryHelper
    {
        [DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
        private static extern int RegQueryInfoKey(
            UIntPtr hkey,
            out StringBuilder lpClass,
            ref uint lpcbClass,
            IntPtr lpReserved,
            out uint lpcSubKeys,
            out uint lpcbMaxSubKeyLen,
            out uint lpcbMaxClassLen,
            out uint lpcValues,
            out uint lpcbMaxValueNameLen,
            out uint lpcbMaxValueLen,
            out uint lpcbSecurityDescriptor,
            ref FILETIME lpftLastWriteTime);
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int RegCloseKey(UIntPtr hKey);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        private static extern int RegOpenKeyEx(
          UIntPtr hKey,
          string subKey,
          int ulOptions,
          int samDesired,
          out UIntPtr hkResult);
        private static DateTime ToDateTime(FILETIME ft)
        {
            IntPtr buf = IntPtr.Zero;
            try
            {
                long[] longArray = new long[1];
                int cb = Marshal.SizeOf(ft);
                buf = Marshal.AllocHGlobal(cb);
                Marshal.StructureToPtr(ft, buf, false);
                Marshal.Copy(buf, longArray, 0, 1);
                return DateTime.FromFileTime(longArray[0]);
            }
            finally
            {
                if (buf != IntPtr.Zero) Marshal.FreeHGlobal(buf);
            }
        }
        public static DateTime? GetDateModified(RegistryHive registryHive, string path)
        {
            var lastModified = new FILETIME();
            var lpcbClass = new uint();
            var lpReserved = new IntPtr();
            UIntPtr key = UIntPtr.Zero;
            try
            {
                try
                {
                    var hive = new UIntPtr(unchecked((uint)registryHive));
                    if (RegOpenKeyEx(hive, path, 0, (int)RegistryRights.ReadKey, out key) != 0)
                    {
                        return null;
                    }
                    uint lpcbSubKeys;
                    uint lpcbMaxKeyLen;
                    uint lpcbMaxClassLen;
                    uint lpcValues;
                    uint maxValueName;
                    uint maxValueLen;
                    uint securityDescriptor;
                    StringBuilder sb;
                    if (RegQueryInfoKey(
                                 key,
                                 out sb,
                                 ref lpcbClass,
                                 lpReserved,
                                 out lpcbSubKeys,
                                 out lpcbMaxKeyLen,
                                 out lpcbMaxClassLen,
                                 out lpcValues,
                                 out maxValueName,
                                 out maxValueLen,
                                 out securityDescriptor,
                                 ref lastModified) != 0)
                    {
                        return null;
                    }
                    var result = ToDateTime(lastModified);
                    return result;
                }
                finally
                {
                    if (key != UIntPtr.Zero)
                        RegCloseKey(key);
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    }
}

用法-控制台应用程序

using System;
using Microsoft.Win32;
using RegistryUtils;
namespace ConsoleApplicationRegistry
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var dateModified = RegistryHelper.GetDateModified(RegistryHive.LocalMachine, @"SYSTEM'Software'Microsoft");
            if(dateModified.HasValue)
                Console.WriteLine("Key Last Modified Date: {0}", dateModified.Value);
            else
                Console.WriteLine("Error... Try again.");
        }
    }
}