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