Hardware/KernelDriver.cs
author moel.mich
Sun, 31 Oct 2010 22:08:47 +0000
changeset 236 763675f19ff4
child 237 9bf70d316cea
permissions -rw-r--r--
Replaced the non-kernel code of WinRing0 with a managed implementation. The new implementation should fix Issue 32 and simplify further work on Issue 46.
moel@236
     1
/*
moel@236
     2
  
moel@236
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@236
     4
moel@236
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@236
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@236
     7
  the License. You may obtain a copy of the License at
moel@236
     8
 
moel@236
     9
  http://www.mozilla.org/MPL/
moel@236
    10
moel@236
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@236
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@236
    13
  for the specific language governing rights and limitations under the License.
moel@236
    14
moel@236
    15
  The Original Code is the Open Hardware Monitor code.
moel@236
    16
moel@236
    17
  The Initial Developer of the Original Code is 
moel@236
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@236
    19
  Portions created by the Initial Developer are Copyright (C) 2010
moel@236
    20
  the Initial Developer. All Rights Reserved.
moel@236
    21
moel@236
    22
  Contributor(s):
moel@236
    23
moel@236
    24
  Alternatively, the contents of this file may be used under the terms of
moel@236
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@236
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@236
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@236
    28
  of those above. If you wish to allow use of your version of this file only
moel@236
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@236
    30
  use your version of this file under the terms of the MPL, indicate your
moel@236
    31
  decision by deleting the provisions above and replace them with the notice
moel@236
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@236
    33
  the provisions above, a recipient may use your version of this file under
moel@236
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@236
    35
 
moel@236
    36
*/
moel@236
    37
moel@236
    38
using System;
moel@236
    39
using System.Runtime.InteropServices;
moel@236
    40
using Microsoft.Win32.SafeHandles;
moel@236
    41
moel@236
    42
namespace OpenHardwareMonitor.Hardware {
moel@236
    43
  internal class KernelDriver {
moel@236
    44
moel@236
    45
    private string id;
moel@236
    46
moel@236
    47
    private SafeFileHandle device; 
moel@236
    48
    
moel@236
    49
    public KernelDriver(string id) {
moel@236
    50
      this.id = id;
moel@236
    51
    }
moel@236
    52
   
moel@236
    53
    public bool Install(string path) {
moel@236
    54
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
    55
        ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
    56
moel@236
    57
      if (manager == IntPtr.Zero)
moel@236
    58
        return false;
moel@236
    59
moel@236
    60
      IntPtr service = NativeMethods.CreateService(manager, id, id,
moel@236
    61
        ServiceAccessRights.SERVICE_ALL_ACCESS,
moel@236
    62
        ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
moel@236
    63
        ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
moel@236
    64
        null);
moel@236
    65
moel@236
    66
      if (service == IntPtr.Zero) {
moel@236
    67
        if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS)
moel@236
    68
          service = NativeMethods.OpenService(manager, id,
moel@236
    69
            ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
    70
        else
moel@236
    71
          return false;
moel@236
    72
      }
moel@236
    73
moel@236
    74
      if (!NativeMethods.StartService(service, 0, null)) {
moel@236
    75
        if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING)
moel@236
    76
          return false;
moel@236
    77
      }
moel@236
    78
moel@236
    79
      NativeMethods.CloseServiceHandle(service);
moel@236
    80
      NativeMethods.CloseServiceHandle(manager);
moel@236
    81
moel@236
    82
      return true;
moel@236
    83
    }
moel@236
    84
moel@236
    85
    public bool Open() {
moel@236
    86
      device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
moel@236
    87
        FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
moel@236
    88
        CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
moel@236
    89
        IntPtr.Zero), true);
moel@236
    90
moel@236
    91
      if (device.IsInvalid) {
moel@236
    92
        device.Close();
moel@236
    93
        device.Dispose();
moel@236
    94
        device = null;
moel@236
    95
      }
moel@236
    96
moel@236
    97
      return device != null;
moel@236
    98
    }
moel@236
    99
moel@236
   100
    public bool IsOpen {
moel@236
   101
      get { return device != null; }
moel@236
   102
    }
moel@236
   103
moel@236
   104
    public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
moel@236
   105
      if (device == null)
moel@236
   106
        return false;
moel@236
   107
moel@236
   108
      uint bytesReturned;
moel@236
   109
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   110
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   111
        null, 0, out bytesReturned, IntPtr.Zero);
moel@236
   112
      return b;
moel@236
   113
    }
moel@236
   114
moel@236
   115
    public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
moel@236
   116
      ref T outBuffer) 
moel@236
   117
    {
moel@236
   118
      if (device == null)
moel@236
   119
        return false;
moel@236
   120
moel@236
   121
      object boxedOutBuffer = outBuffer;
moel@236
   122
      uint bytesReturned;
moel@236
   123
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   124
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   125
        boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
moel@236
   126
        out bytesReturned, IntPtr.Zero);
moel@236
   127
      outBuffer = (T)boxedOutBuffer;
moel@236
   128
      return b;
moel@236
   129
    }
moel@236
   130
moel@236
   131
    public void Close() {
moel@236
   132
      if (device != null) {
moel@236
   133
        device.Close();
moel@236
   134
        device.Dispose();
moel@236
   135
        device = null;
moel@236
   136
      }
moel@236
   137
    }
moel@236
   138
moel@236
   139
    public bool Delete() {
moel@236
   140
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
   141
      ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
   142
moel@236
   143
      if (manager == IntPtr.Zero)
moel@236
   144
        return false;      
moel@236
   145
moel@236
   146
      IntPtr service = NativeMethods.OpenService(manager, id,
moel@236
   147
        ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
   148
moel@236
   149
      if (service == IntPtr.Zero)
moel@236
   150
        return true;
moel@236
   151
moel@236
   152
      ServiceStatus status = new ServiceStatus();
moel@236
   153
      NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
moel@236
   154
        ref status);
moel@236
   155
moel@236
   156
      NativeMethods.DeleteService(service);
moel@236
   157
moel@236
   158
      NativeMethods.CloseServiceHandle(service);
moel@236
   159
      NativeMethods.CloseServiceHandle(manager);
moel@236
   160
      
moel@236
   161
      return true;
moel@236
   162
    }
moel@236
   163
moel@236
   164
    private enum ServiceAccessRights : uint {
moel@236
   165
      SERVICE_ALL_ACCESS = 0xF01FF
moel@236
   166
    }
moel@236
   167
moel@236
   168
    private enum ServiceControlManagerAccessRights : uint {
moel@236
   169
      SC_MANAGER_ALL_ACCESS = 0xF003F
moel@236
   170
    }
moel@236
   171
moel@236
   172
    private enum ServiceType : uint {
moel@236
   173
      SERVICE_KERNEL_DRIVER = 1,
moel@236
   174
      SERVICE_FILE_SYSTEM_DRIVER = 2
moel@236
   175
    }
moel@236
   176
moel@236
   177
    private enum StartType : uint {
moel@236
   178
      SERVICE_BOOT_START = 0,
moel@236
   179
      SERVICE_SYSTEM_START = 1,
moel@236
   180
      SERVICE_AUTO_START = 2,
moel@236
   181
      SERVICE_DEMAND_START = 3,
moel@236
   182
      SERVICE_DISABLED = 4
moel@236
   183
    }
moel@236
   184
moel@236
   185
    private enum ErrorControl : uint {
moel@236
   186
      SERVICE_ERROR_IGNORE = 0,
moel@236
   187
      SERVICE_ERROR_NORMAL = 1,
moel@236
   188
      SERVICE_ERROR_SEVERE = 2,
moel@236
   189
      SERVICE_ERROR_CRITICAL = 3
moel@236
   190
    }
moel@236
   191
moel@236
   192
    private enum ServiceControl : uint {
moel@236
   193
      SERVICE_CONTROL_STOP = 1,
moel@236
   194
      SERVICE_CONTROL_PAUSE = 2,
moel@236
   195
      SERVICE_CONTROL_CONTINUE = 3,
moel@236
   196
      SERVICE_CONTROL_INTERROGATE = 4,
moel@236
   197
      SERVICE_CONTROL_SHUTDOWN = 5,
moel@236
   198
      SERVICE_CONTROL_PARAMCHANGE = 6,
moel@236
   199
      SERVICE_CONTROL_NETBINDADD = 7,
moel@236
   200
      SERVICE_CONTROL_NETBINDREMOVE = 8,
moel@236
   201
      SERVICE_CONTROL_NETBINDENABLE = 9,
moel@236
   202
      SERVICE_CONTROL_NETBINDDISABLE = 10,
moel@236
   203
      SERVICE_CONTROL_DEVICEEVENT = 11,
moel@236
   204
      SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
moel@236
   205
      SERVICE_CONTROL_POWEREVENT = 13,
moel@236
   206
      SERVICE_CONTROL_SESSIONCHANGE = 14
moel@236
   207
    }
moel@236
   208
moel@236
   209
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   210
    private struct ServiceStatus {
moel@236
   211
      public uint dwServiceType;
moel@236
   212
      public uint dwCurrentState;
moel@236
   213
      public uint dwControlsAccepted;
moel@236
   214
      public uint dwWin32ExitCode;
moel@236
   215
      public uint dwServiceSpecificExitCode;
moel@236
   216
      public uint dwCheckPoint;
moel@236
   217
      public uint dwWaitHint;
moel@236
   218
    }
moel@236
   219
moel@236
   220
    private enum FileAccess : uint {
moel@236
   221
      GENERIC_READ = 0x80000000,
moel@236
   222
      GENERIC_WRITE = 0x40000000
moel@236
   223
    }
moel@236
   224
moel@236
   225
    private enum CreationDisposition : uint {
moel@236
   226
      CREATE_NEW = 1,
moel@236
   227
      CREATE_ALWAYS = 2,
moel@236
   228
      OPEN_EXISTING = 3,
moel@236
   229
      OPEN_ALWAYS = 4,
moel@236
   230
      TRUNCATE_EXISTING = 5
moel@236
   231
    }
moel@236
   232
moel@236
   233
    private enum FileAttributes : uint {
moel@236
   234
      FILE_ATTRIBUTE_NORMAL = 0x80
moel@236
   235
    }
moel@236
   236
moel@236
   237
    private const int
moel@236
   238
      ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
moel@236
   239
      ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
moel@236
   240
moel@236
   241
    private static class NativeMethods {
moel@236
   242
      private const string ADVAPI = "advapi32.dll";
moel@236
   243
      private const string KERNEL = "kernel32.dll";
moel@236
   244
moel@236
   245
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   246
      public static extern IntPtr OpenSCManager(string machineName,
moel@236
   247
        string databaseName, ServiceControlManagerAccessRights dwAccess);
moel@236
   248
moel@236
   249
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   250
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   251
      public static extern bool CloseServiceHandle(IntPtr hSCObject);
moel@236
   252
moel@236
   253
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   254
        SetLastError = true)]
moel@236
   255
      public static extern IntPtr CreateService(IntPtr hSCManager,
moel@236
   256
        string lpServiceName, string lpDisplayName, 
moel@236
   257
        ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
moel@236
   258
        StartType dwStartType, ErrorControl dwErrorControl,
moel@236
   259
        string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
moel@236
   260
        string lpDependencies, string lpServiceStartName, string lpPassword);
moel@236
   261
moel@236
   262
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   263
        SetLastError = true)]
moel@236
   264
      public static extern IntPtr OpenService(IntPtr hSCManager,
moel@236
   265
        string lpServiceName, ServiceAccessRights dwDesiredAccess);
moel@236
   266
moel@236
   267
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   268
        SetLastError = true)]
moel@236
   269
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   270
      public static extern bool DeleteService(IntPtr hService);
moel@236
   271
moel@236
   272
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   273
        SetLastError = true)]
moel@236
   274
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   275
      public static extern bool StartService(IntPtr hService, 
moel@236
   276
        uint dwNumServiceArgs, string[] lpServiceArgVectors);
moel@236
   277
moel@236
   278
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   279
        SetLastError = true)]
moel@236
   280
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   281
      public static extern bool ControlService(IntPtr hService,
moel@236
   282
        ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
moel@236
   283
moel@236
   284
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   285
      public static extern bool DeviceIoControl(SafeFileHandle device,
moel@236
   286
        IOControlCode ioControlCode, 
moel@236
   287
        [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
moel@236
   288
        uint inBufferSize,
moel@236
   289
        [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
moel@236
   290
        uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
moel@236
   291
moel@236
   292
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
moel@236
   293
        SetLastError = true)]
moel@236
   294
      public static extern IntPtr CreateFile(string lpFileName,
moel@236
   295
        FileAccess dwDesiredAccess, uint dwShareMode, 
moel@236
   296
        IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
moel@236
   297
        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
moel@236
   298
    }
moel@236
   299
  }
moel@236
   300
}