Saturday, May 18, 2013

Place Outlook Reminders as top window using C#


Place Outlook Reminders as top window using C#

This program subscribes to WMI events and therefore must be run as an admin account.  It can be added to scheduled jobs so it runs automatically.

It is created as a console application and hides its console window to run in the background.
Basically it watches for whenever Outlook kicks off a new thread and if the window heading has Reminder in it, it forces the window to be on top of all others.

using System;
using System.Management;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace OutlookReminder
{
    class Program
    {
        ManagementEventWatcher startThreadWatch;

        static void Main(string[] args)
        {
            //create a processwatcher that will watch for outlook programs that will be getting opened.
            ProcessWatcher processWatcher = new ProcessWatcher("OUTLOOK.EXE");
            //create a list of threadWatchers for each outlook program that is currently open, however...there really should only be one open at a time.
            List<ThreadsWatcher> threadsWatcher = Process.GetProcessesByName("OUTLOOK").ToList().Select(x => new ThreadsWatcher(x.Id)).ToList();
            
            //Hide this console window and let it live in the background.
            WindowControl.ShowWindow(Process.GetCurrentProcess().MainWindowHandle, (int)WindowControl.WindowState.Hide);
            Console.WriteLine("Press ENTER to stop the Outlook reminders to be forced as the top most window.");
            Console.ReadLine();

            //Dispose of the process watcher that is watching for the outlook program to get opened.
            processWatcher.Dispose();
            //Dispose of all the threads that are not null and not disposed of yet.
            threadsWatcher.Where(x => x != null && !x.disposed).ToList().ForEach(x => x.Dispose());
        }
    }
    #region watchers
    public class ProcessWatcher : IDisposable
    {
        ManagementEventWatcher startProcessWatch;
        ManagementEventWatcher stopProcessWatch;
        ThreadsWatcher threadWatcher;
        public string processName { get; private set; }
        public bool disposed { get; private set; }
        public ProcessWatcher(string _processName)
        {
            processName = _processName;
            disposed = false;
            startProcessWatch = new ManagementEventWatcher(new WqlEventQuery(string.Format("Select * from Win32_ProcessStartTrace WHERE ProcessName='{0}'", processName)));
            startProcessWatch.EventArrived += new EventArrivedEventHandler(startProcessWatch_EventArrived);
            startProcessWatch.Start();
            stopProcessWatch = new ManagementEventWatcher(new WqlEventQuery(string.Format("Select * from Win32_ProcessStopTrace WHERE ProcessName='{0}'", processName)));
            stopProcessWatch.EventArrived += new EventArrivedEventHandler(stopProcessWatch_EventArrived);
            stopProcessWatch.Start();
        }
        #region disposeAndFinalize
        ~ProcessWatcher()
        {
            if (startProcessWatch != null)
            {
                startProcessWatch.Stop();
            }
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    startProcessWatch.Stop();
                    startProcessWatch.Dispose();
                    if (threadWatcher != null && !threadWatcher.disposed)
                    {
                        threadWatcher.Dispose();
                    }
                }
                disposed = true;
            }
        }
        #endregion disposeAndFinalize
        void stopProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            if (threadWatcher != null && !threadWatcher.disposed)
            {
                threadWatcher.Dispose();
            }
        }
        void startProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            int processID = 0;
            int.TryParse(e.NewEvent.Properties["ProcessID"].Value.ToString(), out processID);
            threadWatcher = new ThreadsWatcher(processID);
        }
    }
    public class ThreadsWatcher : IDisposable
    {
        ManagementEventWatcher startThreadWatch;
        public bool disposed { get; private set; }
        public int processID { get; private set; }
        #region constructors
        public ThreadsWatcher(int _processID)
        {
            disposed = false;
            processID = _processID;
            startThreadWatch = new ManagementEventWatcher(new WqlEventQuery("Select * from Win32_ThreadStartTrace WHERE ProcessID=" + processID));
            startThreadWatch.EventArrived += new EventArrivedEventHandler(startThreadWatch_EventArrived);
            startThreadWatch.Start();
        }
        #endregion constructors
        #region disposeAndFinalize
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    startThreadWatch.Stop();
                    startThreadWatch.Dispose();
                }
                disposed = true;
            }
        }
        ~ThreadsWatcher()
        {
            if (startThreadWatch != null)
            {
                startThreadWatch.Stop();
            }
        }
        #endregion disposeAndFinalize
        void startThreadWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            int processID = 0;
            int.TryParse(e.NewEvent.Properties["ProcessID"].Value.ToString(), out processID);
            Process outlookProcess = Process.GetProcessById(processID);

            if (outlookProcess.MainWindowTitle.Contains("Reminder"))
            {
                //Place window as TopMost window.
                WindowControl.SetWindowPos(outlookProcess.MainWindowHandle, WindowControl.SpecialWindowHandles.TopMost, 0, 0, 0, 0, WindowControl.SetWindowPosFlags.TopMostFlag);

                //The next 2 commands are use to ensure that if the window is minimized it will still be maximized and displayed.
                //force the window as the foreground window.
                WindowControl.SetForegroundWindow(outlookProcess.MainWindowHandle);
                //Restore the window to be maximized 
                WindowControl.ShowWindow(outlookProcess.MainWindowHandle, (int)WindowControl.WindowState.Restore);
            }
            outlookProcess.Dispose();
        }
    }
    #endregion watchers
    static class WindowControl
    {
        #region WindowControlEnums
        //First few classes are defined to replace an enum however defining it this way we can load any type.
        public static class SpecialWindowHandles
        {
            public static IntPtr
            NoTopMost = new IntPtr(-2),
            TopMost = new IntPtr(-1),
            Top = new IntPtr(0),
            Bottom = new IntPtr(1);
        }
        public static class SetWindowPosFlags
        {
            public static readonly uint
            NoSize = 0x0001,
            NoMove = 0x0002,
            NoZOrder = 0x0004,
            NoRedraw = 0x0008,
            NoActivate = 0x0010,
            DrawFrame = 0x0020,
            FrameChanged = 0x0020,
            ShowsWindow = 0x0040,
            HideWindow = 0x0080,
            NoCopyBits = 0x0100,
            NoOwnerZOrder = 0x0200,
            NoRrPosition = 0x0200,
            NoSendChanging = 0x0400,
            DeferErase = 0x2000,
            AsyncWindowPos = 0x4000,
            TopMostFlag = NoMove | NoSize;
        }

        //Loaded this great enum values from http://www.pinvoke.net/default.aspx/user32.showwindow.  It loads the XML descriptions so you can read
        //the description in the code when you are using it.
        public enum WindowState :uint
        {
            Hide = 0,
            /// <summary>Activates and displays a window. If the window is minimized 
            /// or maximized, the system restores it to its original size and 
            /// position. An application should specify this flag when displaying 
            /// the window for the first time.</summary>
            /// <remarks>See SW_SHOWNORMAL</remarks>
            ShowNormal = 1,
            /// <summary>Activates the window and displays it as a minimized window.</summary>
            /// <remarks>See SW_SHOWMINIMIZED</remarks>
            ShowMinimized = 2,
            /// <summary>Activates the window and displays it as a maximized window.</summary>
            /// <remarks>See SW_SHOWMAXIMIZED</remarks>
            ShowMaximized = 3,
            /// <summary>Maximizes the specified window.</summary>
            /// <remarks>See SW_MAXIMIZE</remarks>
            Maximize = 3,
            /// <summary>Displays a window in its most recent size and position. 
            /// This value is similar to "ShowNormal", except the window is not 
            /// actived.</summary>
            /// <remarks>See SW_SHOWNOACTIVATE</remarks>
            ShowNormalNoActivate = 4,
            /// <summary>Activates the window and displays it in its current size 
            /// and position.</summary>
            /// <remarks>See SW_SHOW</remarks>
            Show = 5,
            /// <summary>Minimizes the specified window and activates the next 
            /// top-level window in the Z order.</summary>
            /// <remarks>See SW_MINIMIZE</remarks>
            Minimize = 6,
            /// <summary>Displays the window as a minimized window. This value is 
            /// similar to "ShowMinimized", except the window is not activated.</summary>
            /// <remarks>See SW_SHOWMINNOACTIVE</remarks>
            ShowMinNoActivate = 7,
            /// <summary>Displays the window in its current size and position. This 
            /// value is similar to "Show", except the window is not activated.</summary>
            /// <remarks>See SW_SHOWNA</remarks>
            ShowNoActivate = 8,
            /// <summary>Activates and displays the window. If the window is 
            /// minimized or maximized, the system restores it to its original size 
            /// and position. An application should specify this flag when restoring 
            /// a minimized window.</summary>
            /// <remarks>See SW_RESTORE</remarks>
            Restore = 9,
            /// <summary>Sets the show state based on the SW_ value specified in the 
            /// STARTUPINFO structure passed to the CreateProcess function by the 
            /// program that started the application.</summary>
            /// <remarks>See SW_SHOWDEFAULT</remarks>
            ShowDefault = 10,
            /// <summary>Windows 2000/XP: Minimizes a window, even if the thread 
            /// that owns the window is hung. This flag should only be used when 
            /// minimizing windows from a different thread.</summary>
            /// <remarks>See SW_FORCEMINIMIZE</remarks>
            ForceMinimized = 11
        }

        #endregion

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.I4)]
        public static extern int SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    }
}

Monday, December 31, 2012

Place Outlook Reminders as top window using PowerShell

Place Outlook Reminders as top window using PowerShell

NOTE: In order for this to work.
        1. It should be in a powershell window and it should not be closed.
        2. Must be run with Admin Privledges.
(For information about WmiEvents read this great site:http://www.ravichaganti.com/blog/?p=1509)
#There are 2 parts to this program. 1. Set up the triggers for when outlook gets opened in the future.
#                                   2. Set up the triggers when outlook is already opened.
try{
#Connect reciever if Outlook is not yet open#
#Create a Trigger which will execute code when a program called 'OUTLOOK.EXE' starts#
Register-WmiEvent -Query "Select * from Win32_ProcessStartTrace WHERE ProcessName='OUTLOOK.EXE'"   `
                  -SourceIdentifier "OutlookProcess"                                               `
                  -Action {     #Get the process ID which is assigned to the Outlook program
                                $ProcessID = $Event.SourceEventArgs.NewEvent.ProcessID;
                                #Create a Trigger which will execute when Outlook starts a new thread#
                                Register-WmiEvent -Query "Select * from Win32_ThreadStartTrace WHERE ProcessID=$ProcessID"   `
                                                  -SourceIdentifier "OutlookThread"                                          `
                                                  -Action {      #Get the threads parent process (The window that started this thread) so we can see if the title on the window has labeled with "Reminder" in it.
                                                                 $ThreadsParentProcess = Get-Process -id $($Event.SourceEventArgs.NewEvent.ProcessID);      
                                                                 if($ThreadsParentProcess.MainWindowTitle.Contains("Reminder")) {
#Expose this C++ method that puts a specified window as the top most window using C# code                                                                
Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class WindowStatus {
     static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
     const UInt32 SWP_NOSIZE = 0x0001;
     const UInt32 SWP_NOMOVE = 0x0002;
     const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
     public static void OnTop(IntPtr hWnd) {
            SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
     }
  }
"@;                    
                                                                      #Call the C# Method that we created in the above statement to place this threads parent process as the top most window.
                                                                      [WindowStatus]::OnTop( $ThreadsParentProcess.MainWindowHandle);
                                                                 }
                                                                 #Remove(Dispose) the $ThreadsParentProcess variable from memory#
                                                                 $ThreadsParentProcess.Dispose();
                                                          }
                                #Force garbage collection to run to make double sure that we have no residue in memorey#
                                [GC]::Collect();
                                #Create a Trigger which will execute when Outlook is closed to remove the triggers we created#
                                Register-WmiEvent -Query "Select * from Win32_ProcessStopTrace WHERE ProcessID=$ProcessID"   `
                                                  -Action {     Unregister-Event -SourceIdentifier "OutlookThread" ; }
                           }
}                          
catch{}                      

#Connect reciever if Outlook is already open#
try{ $ProcessID = $(Get-Process |?{$_.Name -eq "OUTLOOK" } |select Id).Id }
catch{}
if($ProcessID -gt 0) {
                                #Create a Trigger which will execute when Outlook starts a new thread#
                                Register-WmiEvent -Query "Select * from Win32_ThreadStartTrace WHERE ProcessID=$ProcessID"   `
                                                  -SourceIdentifier "OutlookThread"                                          `
                                                  -Action {      #Get the threads parent process (The window that started this thread) so we can see if the title on the window has labeled with "Reminder" in it.
                                                                 $ThreadsParentProcess = Get-Process -id $($Event.SourceEventArgs.NewEvent.ProcessID);      
                                                                 if($ThreadsParentProcess.MainWindowTitle.Contains("Reminder")) {
#In order to expose this C++ method that puts any specified window as the top most window we have to use C# code                                                                 
Add-Type @"
  using System;
  using System.Runtime.InteropServices;
  public class WindowStatus {
     static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
     const UInt32 SWP_NOSIZE = 0x0001;
     const UInt32 SWP_NOMOVE = 0x0002;
     const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
     [DllImport("user32.dll")]
     [return: MarshalAs(UnmanagedType.Bool)]
     public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
    public static void OnTop(IntPtr hWnd) {
            SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
     }
  }
"@;                    
                                                                      #Call the C# Method that we created in the above statement to place this threads parent process as the top most window.
                                                                      [WindowStatus]::OnTop( $ThreadsParentProcess.MainWindowHandle);
                                                                 }
                                                                 #Remove(Dispose) the $ThreadsParentProcess variable from memory#
                                                                 $ThreadsParentProcess.Dispose();
                                                          }
                                #Force garbage collection to run to make double sure that we have no residue in memorey#
                                [GC]::Collect();
                                #Create a Trigger which will execute when Outlook is closed to remove the triggers we created#
                                Register-WmiEvent -Query "Select * from Win32_ProcessStopTrace WHERE ProcessID=$ProcessID"   `
                                                  -Action {     Unregister-Event -SourceIdentifier "OutlookThread" ; }
   
}

Retrieve Windows event information using powershell

Retrieve Windows event information using powershell

An amazing site that has a lot of this information is located here. http://www.ravichaganti.com/blog/?p=1711

To display events that you can attach a script/program to type the following command:
Get-WMIObject -Query "Select * from meta_class Where (__This ISA '__Event') AND (__Class like 'win32%')"

To look at a process save it into an object variable. (For example we'll look at Win32_ProcessStartTrace)
$ProcessStart = Get-WMIObject -list -Class Win32_ProcessStartTrace

 
To display the properties that you can query on type the command below.
$ProcessStart.Properties |select Name
 
The results should look like the following.
Name
----                                                                                                                                                        
ParentProcessID                                                                                                                                             
ProcessID                                                                                                                                                   
ProcessName                                                                                                                                                 
SECURITY_DESCRIPTOR                                                                                                                                         
SessionID                                                                                                                                                   
Sid                                                                                                                                                         
TIME_CREATED 
 
Now that you know the events and its property names you can attach an action to any specific process.  
#Register-WMIEvent using -Query
Register-WmiEvent -Query "Select * from Win32_ProcessStartTrace WHERE ProcessName='notepad.exe'" `                   -Action {Write-Host $Event.SourceEventArgs.NewEvent.ProcessName " New Outlook process created" }
 

How To Deploy applications to IIS using Powershell

How To Deploy applications to IIS

#Additional information on deploying to IIS here http://www.iis.net/learn/manage/powershell/powershell-snap-in-creating-web-sites-web-applications-virtual-directories-and-application-pools
$from = "c:\temp\WebApp\*"
$name = "WebApp"
$to = "C:\inetpub\wwwroot\"+$name+"\"
$physicalPath = $to
#Move the Web Application to the IIS folder
Copy-Item $from $to -recurse -Force

###### Create an application pool and ensure it is using .NET 4   #######
    New-WebAppPool -Name $name -Force
    #To Get The Web Application Object again use the following statement ####$webPool = Get-Item IIS:\AppPools\$name
    $webPool = Get-Item IIS:\AppPools\$name
    $webPool.managedRuntimeVersion = "v4.0"
    $webPool.managedPipelineMode = "Classic"
    $webPool.processModel.loadUserProfile =$true
    $webPool.processModel.logonType = "LogonBatch"
    #If Identity type is ApplicationPoolIdenetity/NetworkService/LocalService/LocalSystem uncomment
    #the Line bellow and comment out the other identityType="SpecificUser,UserName and Password lines
    #$webPool.processModel.identityType = "ApplicationPoolIdentity"
    $webPool.processModel.identityType = "SpecificUser"
    $webPool.processModel.userName = "Gtank1"
    $webPool.processModel.password = "Password1"
    $webPool | Set-Item

    # Create Website
    New-WebSite -Name $name -Port 80 -HostHeader $name -PhysicalPath $physicalPath -Force
    #To Get The Web Site Object again use the following statement #### $WebSite = Get-Item IIS:\Sites\$name
    # Set the Application Pool
    Set-ItemProperty IIS:\Sites\$name ApplicationPool $name
    #Turn on Directory Browsing
    Set-WebConfigurationProperty -filter /system.webServer/directoryBrowse -name enabled -Value $true -PSPath IIS:\Sites\$name
    #Only add the default document if it already hasn't been added
    $DefaultDocument = "Accounts/Default.aspx"
    $ExistingDefaultDocuments = get-webconfigurationproperty -filter /system.webServer/defaultDocument -name files -Location $name #Retrieve all the default documents
    $DefDocFound = $ExistingDefaultDocuments.Collection | where {$_.value -eq $DefaultDocument} #look for the default document that we want to add
    if(!$DefDocFound) {
            #To add the default document globally remove the -Location parameter
            Add-webconfigurationproperty -filter /system.webServer/defaultDocument -name files -value @{value=$DefaultDocument} -Location $name
            #remove-webconfigurationproperty /system.webServer/defaultDocument -name files -atElement @{value=$DefaultDocument} -Location $name
    }
    #Add-WebConfiguration -filter /system.webServer/defaultDocument/files -name enabled -location $name -value @{value="default.aspx"}
    # Update Authentication
    Set-WebConfigurationProperty -filter /system.WebServer/security/authentication/AnonymousAuthentication -name enabled -value true -location $name
    Set-WebConfigurationProperty -filter /system.WebServer/security/authentication/windowsAuthentication -name enabled -value false -location $name
    Set-WebConfigurationProperty -filter /system.WebServer/security/authentication/basicAuthentication -name enabled -value false -location $name
#The code beolow will actually delete the Application pool and Web site that has been created above.
#NOTE:  You must delete the site and application pools that are retrieved from the Servermanager object
#       instead of using get-item otherwise you will get the following error "The configuration object is read only, because it has
#       been committed by a call to ServerManager.CommitChanges(). If write access is required, use ServerManager
#       to get a new reference."
#
<#
   [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
   $iis = New-Object Microsoft.Web.Administration.ServerManager
   Remove-Item $to -recurse -Force
   $WebSite = $iis.Sites["WebApp"]
   $webPool = $iis.ApplicationPools["WebApp"]
   $WebSite.Delete()
   $webPool.Delete()
#>

Create a Group and User using Powershell

Create a Group and User using Powershell

$cmpName = [System.Net.DNS]::GetHostName()
#Load the Computer WinNT(Windows New Technology) into an ADSI (Active Directory Service Interface) defined object.
$computer = [ADSI]("WinNT://$cmpName,computer")
#Join the computer to the Home network named WorkGroup
$computer.JoinDomainOrWorkgroup("WORKGROUP")

#List all the computers users and groups
$computer.Children | Where {$_.SchemaClassName -ne "service"} | Select *Name

#Create A Family Group
$newGroup = $computer.Create("group","Family")
$newGroup.psbase.InvokeSet("description","Family Group")
$newGroup.setinfo()

#Give the Family Group (which includes all members) to the Admin group
$adminGroup = "$cmpName/Administrators,group"
$adminGroup = [adsi]("WinNT://$adminGroup")
$adminGroup.add("WinNT://$cmpName/Family")

#Create a new user
$newuser = $computer.Create("user", "Test")
$newuser.SetPassword("Password1")
$newuser.SetInfo()
$newuser.psbase.InvokeSet('AccountDisabled', $false)
$newuser.psbase.InvokeSet('FullName','FirstName LastName')
$newuser.SetInfo()

#Add user to the Family group
$newGroup.psbase.Invoke("Add","WindNT://"+$newuser.Name)

#List all the groups and users on this computer
$computer.Children | Where {$_.SchemaClassName -eq "group" -or $_.SchemaClassName -eq "user"} | Select SchemaClassName, Name , Path

Order of Priority When Accessing a URL

Order of Priority When Accessing a URL

When accessing web sites the URL address is checked in 3 places prior to accessing it online.
Your computer is defaulted to check in this order:
1. DNS Resolver Cache: 
        a. You can view the contents by opening a PowerShell window and typing: Get-DnsClientCache
        b. You can clear it by typing IPConfig /flushDNS
2. Hosts File:
        a. It is located in C:\Windows\System32\Drivers\etc\Hosts.
        b. You can add custom DNS entries in the hosts file. (creates a custom URL address to a particular URL)
        c. The same web server can have the appearance of hosting multiple domain names on port 80 if a unique host header name is set.  In order to access this site for the new address defined in the host header the Hosts file can be updated to declare the IP address and the domain name.  This is a good first test prior to requesting/implementing a change to the DNS. 

3.DNS
        a.  Stores the same information as what is in the local hosts file but is accessed by all computers/users on the current domain.
4.WINS

Read here to learn how to change the order of this list by tweaking your registry.  http://www.speedguide.net/articles/host-resolution-priority-tweak-1130

Thursday, November 22, 2012

C# How to keep your system from entering sleep mode when running long programs


//Need to include the System.Runtime.InteropServices in order to use the [DllImport] attribute
using System.Runtime.InteropServices;

namespace MyAmazingProgram
{
    public class MyApplication
    {

         //Enable away mode and prevent the sleep idle time-out. For more information read here. http://msdn.microsoft.com/en-us/library/aa373208%28v=vs.85%29.aspx
        SystemState.SetThreadExecutionState(SystemState.ES_CONTINUOUS | SystemState.ES_SYSTEM_REQUIRED | SystemState.ES_AWAYMODE_REQUIRED);
         
        //Execute long running code here...
        // Clear EXECUTION_STATE flags to disable away mode and allow the system to idle to sleep normally.
        SystemState.SetThreadExecutionState(SystemState.ES_CONTINUOUS);
     

    }  
    internal static class SystemState
    {
        // Import SetThreadExecutionState Win32 API and all flags
        [DllImport("kernel32.dll")]
        public static extern uint SetThreadExecutionState(uint esFlags);

        public const uint ES_SYSTEM_REQUIRED = 0x00000001;
        public const uint ES_DISPLAY_REQUIRED = 0x00000002;
        public const uint ES_USER_PRESENT = 0x00000004;
        public const uint ES_AWAYMODE_REQUIRED = 0x00000040;
        public const uint ES_CONTINUOUS = 0x80000000;
    }
}