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