Hardware/KernelDriver.cs
changeset 236 763675f19ff4
child 237 9bf70d316cea
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Hardware/KernelDriver.cs	Sun Oct 31 22:08:47 2010 +0000
     1.3 @@ -0,0 +1,300 @@
     1.4 +/*
     1.5 +  
     1.6 +  Version: MPL 1.1/GPL 2.0/LGPL 2.1
     1.7 +
     1.8 +  The contents of this file are subject to the Mozilla Public License Version
     1.9 +  1.1 (the "License"); you may not use this file except in compliance with
    1.10 +  the License. You may obtain a copy of the License at
    1.11 + 
    1.12 +  http://www.mozilla.org/MPL/
    1.13 +
    1.14 +  Software distributed under the License is distributed on an "AS IS" basis,
    1.15 +  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    1.16 +  for the specific language governing rights and limitations under the License.
    1.17 +
    1.18 +  The Original Code is the Open Hardware Monitor code.
    1.19 +
    1.20 +  The Initial Developer of the Original Code is 
    1.21 +  Michael Möller <m.moeller@gmx.ch>.
    1.22 +  Portions created by the Initial Developer are Copyright (C) 2010
    1.23 +  the Initial Developer. All Rights Reserved.
    1.24 +
    1.25 +  Contributor(s):
    1.26 +
    1.27 +  Alternatively, the contents of this file may be used under the terms of
    1.28 +  either the GNU General Public License Version 2 or later (the "GPL"), or
    1.29 +  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    1.30 +  in which case the provisions of the GPL or the LGPL are applicable instead
    1.31 +  of those above. If you wish to allow use of your version of this file only
    1.32 +  under the terms of either the GPL or the LGPL, and not to allow others to
    1.33 +  use your version of this file under the terms of the MPL, indicate your
    1.34 +  decision by deleting the provisions above and replace them with the notice
    1.35 +  and other provisions required by the GPL or the LGPL. If you do not delete
    1.36 +  the provisions above, a recipient may use your version of this file under
    1.37 +  the terms of any one of the MPL, the GPL or the LGPL.
    1.38 + 
    1.39 +*/
    1.40 +
    1.41 +using System;
    1.42 +using System.Runtime.InteropServices;
    1.43 +using Microsoft.Win32.SafeHandles;
    1.44 +
    1.45 +namespace OpenHardwareMonitor.Hardware {
    1.46 +  internal class KernelDriver {
    1.47 +
    1.48 +    private string id;
    1.49 +
    1.50 +    private SafeFileHandle device; 
    1.51 +    
    1.52 +    public KernelDriver(string id) {
    1.53 +      this.id = id;
    1.54 +    }
    1.55 +   
    1.56 +    public bool Install(string path) {
    1.57 +      IntPtr manager = NativeMethods.OpenSCManager(null, null,
    1.58 +        ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
    1.59 +
    1.60 +      if (manager == IntPtr.Zero)
    1.61 +        return false;
    1.62 +
    1.63 +      IntPtr service = NativeMethods.CreateService(manager, id, id,
    1.64 +        ServiceAccessRights.SERVICE_ALL_ACCESS,
    1.65 +        ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
    1.66 +        ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
    1.67 +        null);
    1.68 +
    1.69 +      if (service == IntPtr.Zero) {
    1.70 +        if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS)
    1.71 +          service = NativeMethods.OpenService(manager, id,
    1.72 +            ServiceAccessRights.SERVICE_ALL_ACCESS);
    1.73 +        else
    1.74 +          return false;
    1.75 +      }
    1.76 +
    1.77 +      if (!NativeMethods.StartService(service, 0, null)) {
    1.78 +        if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING)
    1.79 +          return false;
    1.80 +      }
    1.81 +
    1.82 +      NativeMethods.CloseServiceHandle(service);
    1.83 +      NativeMethods.CloseServiceHandle(manager);
    1.84 +
    1.85 +      return true;
    1.86 +    }
    1.87 +
    1.88 +    public bool Open() {
    1.89 +      device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
    1.90 +        FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
    1.91 +        CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
    1.92 +        IntPtr.Zero), true);
    1.93 +
    1.94 +      if (device.IsInvalid) {
    1.95 +        device.Close();
    1.96 +        device.Dispose();
    1.97 +        device = null;
    1.98 +      }
    1.99 +
   1.100 +      return device != null;
   1.101 +    }
   1.102 +
   1.103 +    public bool IsOpen {
   1.104 +      get { return device != null; }
   1.105 +    }
   1.106 +
   1.107 +    public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
   1.108 +      if (device == null)
   1.109 +        return false;
   1.110 +
   1.111 +      uint bytesReturned;
   1.112 +      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
   1.113 +        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
   1.114 +        null, 0, out bytesReturned, IntPtr.Zero);
   1.115 +      return b;
   1.116 +    }
   1.117 +
   1.118 +    public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
   1.119 +      ref T outBuffer) 
   1.120 +    {
   1.121 +      if (device == null)
   1.122 +        return false;
   1.123 +
   1.124 +      object boxedOutBuffer = outBuffer;
   1.125 +      uint bytesReturned;
   1.126 +      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
   1.127 +        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
   1.128 +        boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
   1.129 +        out bytesReturned, IntPtr.Zero);
   1.130 +      outBuffer = (T)boxedOutBuffer;
   1.131 +      return b;
   1.132 +    }
   1.133 +
   1.134 +    public void Close() {
   1.135 +      if (device != null) {
   1.136 +        device.Close();
   1.137 +        device.Dispose();
   1.138 +        device = null;
   1.139 +      }
   1.140 +    }
   1.141 +
   1.142 +    public bool Delete() {
   1.143 +      IntPtr manager = NativeMethods.OpenSCManager(null, null,
   1.144 +      ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
   1.145 +
   1.146 +      if (manager == IntPtr.Zero)
   1.147 +        return false;      
   1.148 +
   1.149 +      IntPtr service = NativeMethods.OpenService(manager, id,
   1.150 +        ServiceAccessRights.SERVICE_ALL_ACCESS);
   1.151 +
   1.152 +      if (service == IntPtr.Zero)
   1.153 +        return true;
   1.154 +
   1.155 +      ServiceStatus status = new ServiceStatus();
   1.156 +      NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
   1.157 +        ref status);
   1.158 +
   1.159 +      NativeMethods.DeleteService(service);
   1.160 +
   1.161 +      NativeMethods.CloseServiceHandle(service);
   1.162 +      NativeMethods.CloseServiceHandle(manager);
   1.163 +      
   1.164 +      return true;
   1.165 +    }
   1.166 +
   1.167 +    private enum ServiceAccessRights : uint {
   1.168 +      SERVICE_ALL_ACCESS = 0xF01FF
   1.169 +    }
   1.170 +
   1.171 +    private enum ServiceControlManagerAccessRights : uint {
   1.172 +      SC_MANAGER_ALL_ACCESS = 0xF003F
   1.173 +    }
   1.174 +
   1.175 +    private enum ServiceType : uint {
   1.176 +      SERVICE_KERNEL_DRIVER = 1,
   1.177 +      SERVICE_FILE_SYSTEM_DRIVER = 2
   1.178 +    }
   1.179 +
   1.180 +    private enum StartType : uint {
   1.181 +      SERVICE_BOOT_START = 0,
   1.182 +      SERVICE_SYSTEM_START = 1,
   1.183 +      SERVICE_AUTO_START = 2,
   1.184 +      SERVICE_DEMAND_START = 3,
   1.185 +      SERVICE_DISABLED = 4
   1.186 +    }
   1.187 +
   1.188 +    private enum ErrorControl : uint {
   1.189 +      SERVICE_ERROR_IGNORE = 0,
   1.190 +      SERVICE_ERROR_NORMAL = 1,
   1.191 +      SERVICE_ERROR_SEVERE = 2,
   1.192 +      SERVICE_ERROR_CRITICAL = 3
   1.193 +    }
   1.194 +
   1.195 +    private enum ServiceControl : uint {
   1.196 +      SERVICE_CONTROL_STOP = 1,
   1.197 +      SERVICE_CONTROL_PAUSE = 2,
   1.198 +      SERVICE_CONTROL_CONTINUE = 3,
   1.199 +      SERVICE_CONTROL_INTERROGATE = 4,
   1.200 +      SERVICE_CONTROL_SHUTDOWN = 5,
   1.201 +      SERVICE_CONTROL_PARAMCHANGE = 6,
   1.202 +      SERVICE_CONTROL_NETBINDADD = 7,
   1.203 +      SERVICE_CONTROL_NETBINDREMOVE = 8,
   1.204 +      SERVICE_CONTROL_NETBINDENABLE = 9,
   1.205 +      SERVICE_CONTROL_NETBINDDISABLE = 10,
   1.206 +      SERVICE_CONTROL_DEVICEEVENT = 11,
   1.207 +      SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
   1.208 +      SERVICE_CONTROL_POWEREVENT = 13,
   1.209 +      SERVICE_CONTROL_SESSIONCHANGE = 14
   1.210 +    }
   1.211 +
   1.212 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.213 +    private struct ServiceStatus {
   1.214 +      public uint dwServiceType;
   1.215 +      public uint dwCurrentState;
   1.216 +      public uint dwControlsAccepted;
   1.217 +      public uint dwWin32ExitCode;
   1.218 +      public uint dwServiceSpecificExitCode;
   1.219 +      public uint dwCheckPoint;
   1.220 +      public uint dwWaitHint;
   1.221 +    }
   1.222 +
   1.223 +    private enum FileAccess : uint {
   1.224 +      GENERIC_READ = 0x80000000,
   1.225 +      GENERIC_WRITE = 0x40000000
   1.226 +    }
   1.227 +
   1.228 +    private enum CreationDisposition : uint {
   1.229 +      CREATE_NEW = 1,
   1.230 +      CREATE_ALWAYS = 2,
   1.231 +      OPEN_EXISTING = 3,
   1.232 +      OPEN_ALWAYS = 4,
   1.233 +      TRUNCATE_EXISTING = 5
   1.234 +    }
   1.235 +
   1.236 +    private enum FileAttributes : uint {
   1.237 +      FILE_ATTRIBUTE_NORMAL = 0x80
   1.238 +    }
   1.239 +
   1.240 +    private const int
   1.241 +      ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
   1.242 +      ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
   1.243 +
   1.244 +    private static class NativeMethods {
   1.245 +      private const string ADVAPI = "advapi32.dll";
   1.246 +      private const string KERNEL = "kernel32.dll";
   1.247 +
   1.248 +      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
   1.249 +      public static extern IntPtr OpenSCManager(string machineName,
   1.250 +        string databaseName, ServiceControlManagerAccessRights dwAccess);
   1.251 +
   1.252 +      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
   1.253 +      [return: MarshalAs(UnmanagedType.Bool)]
   1.254 +      public static extern bool CloseServiceHandle(IntPtr hSCObject);
   1.255 +
   1.256 +      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   1.257 +        SetLastError = true)]
   1.258 +      public static extern IntPtr CreateService(IntPtr hSCManager,
   1.259 +        string lpServiceName, string lpDisplayName, 
   1.260 +        ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
   1.261 +        StartType dwStartType, ErrorControl dwErrorControl,
   1.262 +        string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
   1.263 +        string lpDependencies, string lpServiceStartName, string lpPassword);
   1.264 +
   1.265 +      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   1.266 +        SetLastError = true)]
   1.267 +      public static extern IntPtr OpenService(IntPtr hSCManager,
   1.268 +        string lpServiceName, ServiceAccessRights dwDesiredAccess);
   1.269 +
   1.270 +      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   1.271 +        SetLastError = true)]
   1.272 +      [return: MarshalAs(UnmanagedType.Bool)]
   1.273 +      public static extern bool DeleteService(IntPtr hService);
   1.274 +
   1.275 +      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   1.276 +        SetLastError = true)]
   1.277 +      [return: MarshalAs(UnmanagedType.Bool)]
   1.278 +      public static extern bool StartService(IntPtr hService, 
   1.279 +        uint dwNumServiceArgs, string[] lpServiceArgVectors);
   1.280 +
   1.281 +      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   1.282 +        SetLastError = true)]
   1.283 +      [return: MarshalAs(UnmanagedType.Bool)]
   1.284 +      public static extern bool ControlService(IntPtr hService,
   1.285 +        ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
   1.286 +
   1.287 +      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   1.288 +      public static extern bool DeviceIoControl(SafeFileHandle device,
   1.289 +        IOControlCode ioControlCode, 
   1.290 +        [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
   1.291 +        uint inBufferSize,
   1.292 +        [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
   1.293 +        uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
   1.294 +
   1.295 +      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
   1.296 +        SetLastError = true)]
   1.297 +      public static extern IntPtr CreateFile(string lpFileName,
   1.298 +        FileAccess dwDesiredAccess, uint dwShareMode, 
   1.299 +        IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
   1.300 +        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
   1.301 +    }
   1.302 +  }
   1.303 +}