using System;
using System.Text;
using System.Runtime.InteropServices;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;

namespace CSharpDemo
{
    class Program
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern int WaitForSingleObject(uint hHandle, int dwMilliseconds);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern uint CloseHandle(uint hHandle);

        [DllImport("kernel32.dll")]
        private extern static void GetLocalTime(ref SYSTEMTIME lpSystemTime);

        [DllImport("kernel32.dll")]
        private extern static void GetSystemTimeAsFileTime(ref FILETIME lpFileTime);

        //
        // you will probably put DTHRes32.dll in your program's folder or somewhere in the system path
        // if not, you will have to specify the absolute path in the DllImport statements

        [DllImport("DTHRes32.dll", SetLastError = true)]   // for x64 build, use DTHres64.dll instead
        public static extern bool GetDomainTimeStatus(ref uint iStatus);

        [DllImport("DTHRes32.dll", SetLastError = true)]   // for x64 build, use DTHres64.dll instead
        public static extern uint GetDomainTimeNotifyHandle();

        [DllImport("DTHRes32.dll",SetLastError = true)]
        private extern static int GetLocalDomainTime(ref SYSTEMTIME lpSystemTime);

        [DllImport("DTHRes32.dll", SetLastError = true)]
        private extern static bool GetDomainTimeAsFileTime(ref FILETIME lpFileTime);

        enum SYNC_STATUSES { SYNC_STATUS_INVALID, SYNC_STATUS_UNKNOWN, SYNC_STATUS_CHECKING, SYNC_STATUS_SYNCED, SYNC_STATUS_UNSYNCED };

        static uint LastStatus = 0;
        private struct SYSTEMTIME
        {
            public ushort wYear;
            public ushort wMonth;
            public ushort wDayOfWeek;
            public ushort wDay;
            public ushort wHour;
            public ushort wMinute;
            public ushort wSecond;
            public ushort wMilliseconds;
        }
        
        static bool ShowStatus()
        {
            uint iStatus;
            bool bSuccess;
            int dwError;
            FILETIME ft = new FILETIME();
            FILETIME dt = new FILETIME();
            SYSTEMTIME st = new SYSTEMTIME();

            dwError = GetLocalDomainTime(ref st);

            for (uint x = 0; x < 25; x++)
            {
                GetSystemTimeAsFileTime(ref ft);
                bSuccess = GetDomainTimeAsFileTime(ref dt);

                System.Console.Write(
                    "OS=" + ft.dwHighDateTime.ToString() + ":" + ft.dwLowDateTime.ToString() +
                    "   DT=" + dt.dwHighDateTime.ToString() + ":" + dt.dwLowDateTime.ToString());
                
                if (bSuccess)   System.Console.WriteLine(" - high resolution");
                else            System.Console.WriteLine(" - system resolution");

                System.Threading.Thread.Sleep(1);
            }


            iStatus = 0;
            bSuccess = GetDomainTimeStatus(ref iStatus);
            if (bSuccess)
            {
                if (iStatus != LastStatus)
                {
                    LastStatus = iStatus;

                    System.Console.Write("Status = ");
                    if      (iStatus == (uint)SYNC_STATUSES.SYNC_STATUS_INVALID)    System.Console.WriteLine("Invalid");
                    else if (iStatus == (uint)SYNC_STATUSES.SYNC_STATUS_UNKNOWN)    System.Console.WriteLine("Unknown");
                    else if (iStatus == (uint)SYNC_STATUSES.SYNC_STATUS_CHECKING)   System.Console.WriteLine("Checking");
                    else if (iStatus == (uint)SYNC_STATUSES.SYNC_STATUS_SYNCED)     System.Console.WriteLine("Synchronized");
                    else                                                            System.Console.WriteLine("Not synchronized");
                }
                return true;
            }
            else
            {
                dwError = Marshal.GetLastWin32Error();
                System.Console.WriteLine("Unable to load Domain Time status; error = " + dwError);
                if      (dwError == 2)      System.Console.WriteLine("The shared memory section was not found (is Domain Time running?)");
                else if (dwError == 5)      System.Console.WriteLine("Access was denied. Domain Time is probably not running.");
                else if (dwError == 1062)   System.Console.WriteLine("The Domain Time service isn't running.");
                else if (dwError == 10)     System.Console.WriteLine("The DTHResxx.dll version is not compatible.");
                return false;
            }
        }

        static void Main()
        {
            uint hHandle;
            uint dwError;

            System.Console.WriteLine("Domain Time Interface Example in C#");

            hHandle = GetDomainTimeNotifyHandle();
            if (hHandle == 0)
            {
                System.Console.WriteLine("Unable to obtain notify handle; error " + Marshal.GetLastWin32Error());
                return;
            }
            System.Console.WriteLine("Hit ^C to terminate...\n");

            while (ShowStatus())
            {
                WaitForSingleObject(hHandle, -1);   // using an infinite wait here
            }
            dwError = CloseHandle(hHandle);
        }
    }
}