Hi all!
I am trying to find the last write time of a registry key using the following code but this code is showing the time with offset of some minutes i.e. if actual time is 4:29 it will give 4:26. i can't figure out the problem in the code. So please help me in figuring out the problem in the code. Thanks in advance.

using System;
using System.Runtime.InteropServices;//used for declaring api's
using System.Text;
using Microsoft.Win32.SafeHandles;


namespace USB_Tracker
{
    public class RegAPIWrapper
    {
        private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(-2147483648);
        private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(-2147483647);
        private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(-2147483646);
        private static readonly IntPtr HKEY_USERS = new IntPtr(-2147483645);
        private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(-2147483644);
        private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(-2147483643);
        private static readonly IntPtr HKEY_DYN_DATA = new IntPtr(-2147483642);

        // Access types for the "samDesired" parameter of "RegOpenKeyEx".
        private const int KEY_QUERY_VALUE = 1;
        private const int KEY_SET_VALUE = 2;
        private const int KEY_CREATE_SUB_KEY = 4;
        private const int KEY_ENUMERATE_SUB_KEYS = 8;
        private const int KEY_NOTIFY = 16;
        private const int KEY_CREATE_LINK = 32;
        private const int KEY_WRITE = 0x20006;
        private const int KEY_READ = 0x20019;
        private const int KEY_ALL_ACCESS = 0xF003F;
        public DateTime last;
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        private static extern int RegOpenKeyEx(
            SafeRegistryHandle hKey,
            string lpSubKey,
            int ulOptions,
            int samDesired,
            out SafeRegistryHandle hkResult);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        private static extern int RegQueryInfoKey(
            SafeRegistryHandle hKey,
            StringBuilder lpClass,
            int[] lpcbClass,
            IntPtr lpReserved_MustBeZero,
            ref int lpcSubKeys,
            int[] lpcbMaxSubKeyLen,
            int[] lpcbMaxClassLen,
            ref int lpcValues,
            int[] lpcbMaxValueNameLen,
            int[] lpcbMaxValueLen,
            int[] lpcbSecurityDescriptor,
            int[] lpftLastWriteTime);

        public static DateTime GetRegKeyLastWriteTime(string regkeyname)
        {
            string[] parts = regkeyname.Split('\\');
            string sHive = parts[0];
            string[] SubkeyParts = new string[parts.Length - 1];
            Array.Copy(parts, 1, SubkeyParts, 0, SubkeyParts.Length);
            string sSubKey = string.Join("\\", SubkeyParts);

            SafeRegistryHandle hRootKey = null;

            switch (sHive)
            {
                case "HKEY_CLASSES_ROOT": hRootKey = new SafeRegistryHandle(HKEY_CLASSES_ROOT, true); break;
                case "HKEY_CURRENT_USER": hRootKey = new SafeRegistryHandle(HKEY_CURRENT_USER, true); break;
                case "HKEY_LOCAL_MACHINE": hRootKey = new SafeRegistryHandle(HKEY_LOCAL_MACHINE, true); break;
                case "HKEY_USERS": hRootKey = new SafeRegistryHandle(HKEY_USERS, true); break;
                case "HKEY_PERFORMANCE_DATA": hRootKey = new SafeRegistryHandle(HKEY_PERFORMANCE_DATA, true); break;
                case "HKEY_CURRENT_CONFIG": hRootKey = new SafeRegistryHandle(HKEY_CURRENT_CONFIG, true); break;
                case "HKEY_DYN_DATA": hRootKey = new SafeRegistryHandle(HKEY_DYN_DATA, true); break;
            }

            try
            {
                SafeRegistryHandle hSubKey = null;

                int iErrorCode = RegOpenKeyEx(hRootKey, sSubKey, 0, KEY_READ, out hSubKey);


                int lpcSubKeys = 0;
                int lpcValues = 0;
                int[] lpftLastWriteTime = new int[2];

                iErrorCode = RegAPIWrapper.RegQueryInfoKey(hSubKey, null, null, IntPtr.Zero,
                    ref lpcSubKeys, null, null, ref lpcValues, null, null, null, lpftLastWriteTime);


                long LastWriteTime = (((long)lpftLastWriteTime[1]) << 32) + (-(lpftLastWriteTime[0]));

                DateTime lastWrite = DateTime.FromFileTime(LastWriteTime);
                return lastWrite;


            }

            finally
            {
                if (hRootKey != null && !hRootKey.IsClosed)
                {
                    hRootKey.Close();
                }

            }
        }

    }

    public sealed class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        public SafeRegistryHandle() : base(true) { }

        public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle)
            : base(ownsHandle)
        {
            base.SetHandle(preexistingHandle);
        }

        [DllImport("advapi32.dll")]
        private static extern int RegCloseKey(IntPtr hKey);

        protected override bool ReleaseHandle()
        {
            return (RegCloseKey(base.handle) == 0);
        }
    }
}

Recommended Answers

All 4 Replies

I don't see it just reading it quickly, however I do have a suggestion. Set a breakpoint near the top and step through slowing looking at the value of each variable as it moves through. See if you grab the correct time at first and it changes later or if you grab the wrong time from the beginning.

This seems to work. Changed int to uint

using System;
using System.Runtime.InteropServices;//used for declaring api's
using System.Text;
using Microsoft.Win32.SafeHandles;

namespace QueryRegKey
{
    public class RegAPIWrapper
    {
        private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(-2147483648);
        private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(-2147483647);
        private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(-2147483646);
        private static readonly IntPtr HKEY_USERS = new IntPtr(-2147483645);
        private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(-2147483644);
        private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(-2147483643);
        private static readonly IntPtr HKEY_DYN_DATA = new IntPtr(-2147483642);

        // Access types for the "samDesired" parameter of "RegOpenKeyEx".
        private const int KEY_QUERY_VALUE = 1;
        private const int KEY_SET_VALUE = 2;
        private const int KEY_CREATE_SUB_KEY = 4;
        private const int KEY_ENUMERATE_SUB_KEYS = 8;
        private const int KEY_NOTIFY = 16;
        private const int KEY_CREATE_LINK = 32;
        private const int KEY_WRITE = 0x20006;
        private const int KEY_READ = 0x20019;
        private const int KEY_ALL_ACCESS = 0xF003F;
        public DateTime last;

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        private static extern int RegOpenKeyEx(
        SafeRegistryHandle hKey,
        string lpSubKey,
        uint ulOptions,
        uint samDesired,
        out SafeRegistryHandle hkResult);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        private static extern int RegQueryInfoKey(
        SafeRegistryHandle hKey,
        StringBuilder lpClass,
        uint[] lpcbClass,
        IntPtr lpReserved_MustBeZero,
        ref uint lpcSubKeys,
        uint[] lpcbMaxSubKeyLen,
        uint[] lpcbMaxClassLen,
        ref uint lpcValues,
        uint[] lpcbMaxValueNameLen,
        uint[] lpcbMaxValueLen,
        uint[] lpcbSecurityDescriptor,
        uint[] lpftLastWriteTime);

        public static DateTime GetRegKeyLastWriteTime(string regkeyname)
        {
            string[] parts = regkeyname.Split('\\');
            string sHive = parts[0];
            string[] SubkeyParts = new string[parts.Length - 1];
            Array.Copy(parts, 1, SubkeyParts, 0, SubkeyParts.Length);
            string sSubKey = string.Join("\\", SubkeyParts);

            SafeRegistryHandle hRootKey = null;

            switch (sHive)
            {
                case "HKEY_CLASSES_ROOT": hRootKey = new SafeRegistryHandle(HKEY_CLASSES_ROOT, true); break;
                case "HKEY_CURRENT_USER": hRootKey = new SafeRegistryHandle(HKEY_CURRENT_USER, true); break;
                case "HKEY_LOCAL_MACHINE": hRootKey = new SafeRegistryHandle(HKEY_LOCAL_MACHINE, true); break;
                case "HKEY_USERS": hRootKey = new SafeRegistryHandle(HKEY_USERS, true); break;
                case "HKEY_PERFORMANCE_DATA": hRootKey = new SafeRegistryHandle(HKEY_PERFORMANCE_DATA, true); break;
                case "HKEY_CURRENT_CONFIG": hRootKey = new SafeRegistryHandle(HKEY_CURRENT_CONFIG, true); break;
                case "HKEY_DYN_DATA": hRootKey = new SafeRegistryHandle(HKEY_DYN_DATA, true); break;
            }

            try
            {
                SafeRegistryHandle hSubKey = null;

                int iErrorCode = RegOpenKeyEx(hRootKey, sSubKey, 0, KEY_READ, out hSubKey);


                uint lpcSubKeys = 0;
                uint lpcValues = 0;
                uint[] lpftLastWriteTime = new uint[2];

                iErrorCode = RegAPIWrapper.RegQueryInfoKey(hSubKey, null, null, IntPtr.Zero,
                ref lpcSubKeys, null, null, ref lpcValues, null, null, null, lpftLastWriteTime);


                long LastWriteTime = (((long)lpftLastWriteTime[1]) << 32) + lpftLastWriteTime[0];

                DateTime lastWrite = DateTime.FromFileTime(LastWriteTime);
                return lastWrite;


            }

            finally
            {
                if (hRootKey != null && !hRootKey.IsClosed)
                {
                    hRootKey.Close();
                }

            }
        }

    }

    public sealed class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        public SafeRegistryHandle() : base(true) { }

        public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle)
            : base(ownsHandle)
        {
            base.SetHandle(preexistingHandle);
        }

        [DllImport("advapi32.dll")]
        private static extern int RegCloseKey(IntPtr hKey);

        protected override bool ReleaseHandle()
        {
            return (RegCloseKey(base.handle) == 0);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string regKeyName = @"HKEY_LOCAL_MACHINE\Software\Chip";
            DateTime lastWriteTime = RegAPIWrapper.GetRegKeyLastWriteTime(regKeyName);

        }
    }
}

Just a question: Why use interop vs the Registry class?

I think he did it for RegQueryInfoKey. I don't think the Microsoft.Win32 namespace provides a way to get the last write time. If you do know of a C#-only way, please post.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.