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

时间:2015-11-14 12:25:31

标签: c# winapi dllimport

我的目标是获得某个寄存器的最后写入时间。 使用以下方法获取寄存器即时值:

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

2 个答案:

答案 0 :(得分:1)

RegQueryInfoKey替换

的声明中
UIntPtr hkey

SafeRegistryHandle handle

并传递mKey.Handle

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

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

并声明这样的参数:

out FILETIME lpftLastWriteTime

或者正如汉斯帮助评论一样,请使用long

out long lpftLastWriteTime

然后可以直接传递给

DateTime.FromFileTimeUtc()

其他一些评论:

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

我猜你是从pinvoke.net的宣言开始的。可悲的是,这些往往质量很差。

答案 1 :(得分:0)

这是一个完整的实现:

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的其他方式 - 将文件时间更改为当前时间"
  6. 守则:

    代码包含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.");
            }
        }
    }