Hardware/KernelDriver.cs
author StephaneLenclud
Thu, 18 Apr 2013 19:51:05 +0200
branchMiniDisplay
changeset 443 8c139748f179
parent 367 45215572a774
permissions -rw-r--r--
FrontView can now display time when not packed.
Now waiting 4 ticks before cycling.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2010-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.IO;
    13 using System.Runtime.InteropServices;
    14 using System.Security.AccessControl;
    15 using Microsoft.Win32.SafeHandles;
    16 
    17 namespace OpenHardwareMonitor.Hardware {
    18   internal class KernelDriver {
    19 
    20     private string id;
    21 
    22     private SafeFileHandle device; 
    23     
    24     public KernelDriver(string id) {
    25       this.id = id;
    26     }
    27    
    28     public bool Install(string path, out string errorMessage) {
    29       IntPtr manager = NativeMethods.OpenSCManager(null, null,
    30         ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
    31 
    32       if (manager == IntPtr.Zero) {
    33         errorMessage = "OpenSCManager returned zero.";
    34         return false;
    35       }
    36 
    37       IntPtr service = NativeMethods.CreateService(manager, id, id,
    38         ServiceAccessRights.SERVICE_ALL_ACCESS,
    39         ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
    40         ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
    41         null);
    42 
    43       if (service == IntPtr.Zero) {
    44         if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS) {
    45           errorMessage = "Service already exists";
    46           return false;
    47         } else {
    48           errorMessage = "CreateService returned the error: " +
    49             Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()).Message;
    50           NativeMethods.CloseServiceHandle(manager);
    51           return false;
    52         }
    53       }
    54 
    55       if (!NativeMethods.StartService(service, 0, null)) {
    56         if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING) {
    57           errorMessage = "StartService returned the error: " +
    58             Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()).Message;
    59           NativeMethods.CloseServiceHandle(service);
    60           NativeMethods.CloseServiceHandle(manager);
    61           return false;
    62         }
    63       }
    64 
    65       NativeMethods.CloseServiceHandle(service);
    66       NativeMethods.CloseServiceHandle(manager);
    67       
    68       try {
    69         // restrict the driver access to system (SY) and builtin admins (BA)
    70         // TODO: replace with a call to IoCreateDeviceSecure in the driver
    71         FileSecurity fileSecurity = File.GetAccessControl(@"\\.\" + id);
    72         fileSecurity.SetSecurityDescriptorSddlForm(
    73           "O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
    74         File.SetAccessControl(@"\\.\" + id, fileSecurity);
    75       } catch { }
    76 
    77       errorMessage = null;
    78       return true;
    79     }
    80 
    81     public bool Open() {
    82       device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
    83         FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
    84         CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
    85         IntPtr.Zero), true);
    86 
    87       if (device.IsInvalid) {
    88         device.Close();
    89         device.Dispose();
    90         device = null;
    91       }
    92 
    93       return device != null;
    94     }
    95 
    96     public bool IsOpen {
    97       get { return device != null; }
    98     }
    99 
   100     public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
   101       if (device == null)
   102         return false;
   103 
   104       uint bytesReturned;
   105       bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
   106         inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
   107         null, 0, out bytesReturned, IntPtr.Zero);
   108       return b;
   109     }
   110 
   111     public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
   112       ref T outBuffer) 
   113     {
   114       if (device == null)
   115         return false;
   116 
   117       object boxedOutBuffer = outBuffer;
   118       uint bytesReturned;
   119       bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
   120         inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
   121         boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
   122         out bytesReturned, IntPtr.Zero);
   123       outBuffer = (T)boxedOutBuffer;
   124       return b;
   125     }
   126 
   127     public void Close() {
   128       if (device != null) {
   129         device.Close();
   130         device.Dispose();
   131         device = null;
   132       }
   133     }
   134 
   135     public bool Delete() {
   136       IntPtr manager = NativeMethods.OpenSCManager(null, null,
   137       ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
   138 
   139       if (manager == IntPtr.Zero)
   140         return false;      
   141 
   142       IntPtr service = NativeMethods.OpenService(manager, id,
   143         ServiceAccessRights.SERVICE_ALL_ACCESS);
   144 
   145       if (service == IntPtr.Zero)
   146         return true;
   147 
   148       ServiceStatus status = new ServiceStatus();
   149       NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
   150         ref status);
   151 
   152       NativeMethods.DeleteService(service);
   153 
   154       NativeMethods.CloseServiceHandle(service);
   155       NativeMethods.CloseServiceHandle(manager);
   156       
   157       return true;
   158     }
   159 
   160     private enum ServiceAccessRights : uint {
   161       SERVICE_ALL_ACCESS = 0xF01FF
   162     }
   163 
   164     private enum ServiceControlManagerAccessRights : uint {
   165       SC_MANAGER_ALL_ACCESS = 0xF003F
   166     }
   167 
   168     private enum ServiceType : uint {
   169       SERVICE_KERNEL_DRIVER = 1,
   170       SERVICE_FILE_SYSTEM_DRIVER = 2
   171     }
   172 
   173     private enum StartType : uint {
   174       SERVICE_BOOT_START = 0,
   175       SERVICE_SYSTEM_START = 1,
   176       SERVICE_AUTO_START = 2,
   177       SERVICE_DEMAND_START = 3,
   178       SERVICE_DISABLED = 4
   179     }
   180 
   181     private enum ErrorControl : uint {
   182       SERVICE_ERROR_IGNORE = 0,
   183       SERVICE_ERROR_NORMAL = 1,
   184       SERVICE_ERROR_SEVERE = 2,
   185       SERVICE_ERROR_CRITICAL = 3
   186     }
   187 
   188     private enum ServiceControl : uint {
   189       SERVICE_CONTROL_STOP = 1,
   190       SERVICE_CONTROL_PAUSE = 2,
   191       SERVICE_CONTROL_CONTINUE = 3,
   192       SERVICE_CONTROL_INTERROGATE = 4,
   193       SERVICE_CONTROL_SHUTDOWN = 5,
   194       SERVICE_CONTROL_PARAMCHANGE = 6,
   195       SERVICE_CONTROL_NETBINDADD = 7,
   196       SERVICE_CONTROL_NETBINDREMOVE = 8,
   197       SERVICE_CONTROL_NETBINDENABLE = 9,
   198       SERVICE_CONTROL_NETBINDDISABLE = 10,
   199       SERVICE_CONTROL_DEVICEEVENT = 11,
   200       SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
   201       SERVICE_CONTROL_POWEREVENT = 13,
   202       SERVICE_CONTROL_SESSIONCHANGE = 14
   203     }
   204 
   205     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   206     private struct ServiceStatus {
   207       public uint dwServiceType;
   208       public uint dwCurrentState;
   209       public uint dwControlsAccepted;
   210       public uint dwWin32ExitCode;
   211       public uint dwServiceSpecificExitCode;
   212       public uint dwCheckPoint;
   213       public uint dwWaitHint;
   214     }
   215 
   216     private enum FileAccess : uint {
   217       GENERIC_READ = 0x80000000,
   218       GENERIC_WRITE = 0x40000000
   219     }
   220 
   221     private enum CreationDisposition : uint {
   222       CREATE_NEW = 1,
   223       CREATE_ALWAYS = 2,
   224       OPEN_EXISTING = 3,
   225       OPEN_ALWAYS = 4,
   226       TRUNCATE_EXISTING = 5
   227     }
   228 
   229     private enum FileAttributes : uint {
   230       FILE_ATTRIBUTE_NORMAL = 0x80
   231     }
   232 
   233     private const int
   234       ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
   235       ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
   236 
   237     private static class NativeMethods {
   238       private const string ADVAPI = "advapi32.dll";
   239       private const string KERNEL = "kernel32.dll";
   240 
   241       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
   242       public static extern IntPtr OpenSCManager(string machineName,
   243         string databaseName, ServiceControlManagerAccessRights dwAccess);
   244 
   245       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
   246       [return: MarshalAs(UnmanagedType.Bool)]
   247       public static extern bool CloseServiceHandle(IntPtr hSCObject);
   248 
   249       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   250         SetLastError = true)]
   251       public static extern IntPtr CreateService(IntPtr hSCManager,
   252         string lpServiceName, string lpDisplayName, 
   253         ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
   254         StartType dwStartType, ErrorControl dwErrorControl,
   255         string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
   256         string lpDependencies, string lpServiceStartName, string lpPassword);
   257 
   258       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   259         SetLastError = true)]
   260       public static extern IntPtr OpenService(IntPtr hSCManager,
   261         string lpServiceName, ServiceAccessRights dwDesiredAccess);
   262 
   263       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   264         SetLastError = true)]
   265       [return: MarshalAs(UnmanagedType.Bool)]
   266       public static extern bool DeleteService(IntPtr hService);
   267 
   268       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   269         SetLastError = true)]
   270       [return: MarshalAs(UnmanagedType.Bool)]
   271       public static extern bool StartService(IntPtr hService, 
   272         uint dwNumServiceArgs, string[] lpServiceArgVectors);
   273 
   274       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   275         SetLastError = true)]
   276       [return: MarshalAs(UnmanagedType.Bool)]
   277       public static extern bool ControlService(IntPtr hService,
   278         ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
   279 
   280       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   281       public static extern bool DeviceIoControl(SafeFileHandle device,
   282         IOControlCode ioControlCode, 
   283         [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
   284         uint inBufferSize,
   285         [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
   286         uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
   287 
   288       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
   289         SetLastError = true)]
   290       public static extern IntPtr CreateFile(string lpFileName,
   291         FileAccess dwDesiredAccess, uint dwShareMode, 
   292         IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
   293         FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
   294     }
   295   }
   296 }