Added a few checks and delays to the driver loading code to increase the chance of loading the driver.
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/.
7 Copyright (C) 2010-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
13 using System.Runtime.InteropServices;
14 using System.Security.AccessControl;
15 using Microsoft.Win32.SafeHandles;
17 namespace OpenHardwareMonitor.Hardware {
18 internal class KernelDriver {
22 private SafeFileHandle device;
24 public KernelDriver(string id) {
28 public bool Install(string path, out string errorMessage) {
29 IntPtr manager = NativeMethods.OpenSCManager(null, null,
30 ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
32 if (manager == IntPtr.Zero) {
33 errorMessage = "OpenSCManager returned zero.";
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,
43 if (service == IntPtr.Zero) {
44 if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS)
45 service = NativeMethods.OpenService(manager, id,
46 ServiceAccessRights.SERVICE_ALL_ACCESS);
48 errorMessage = "CreateService returned the error: " +
49 Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()).Message;
50 NativeMethods.CloseServiceHandle(manager);
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);
65 NativeMethods.CloseServiceHandle(service);
66 NativeMethods.CloseServiceHandle(manager);
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);
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,
87 if (device.IsInvalid) {
93 return device != null;
97 get { return device != null; }
100 public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
105 bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
106 inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
107 null, 0, out bytesReturned, IntPtr.Zero);
111 public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer,
117 object boxedOutBuffer = outBuffer;
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;
127 public void Close() {
128 if (device != null) {
135 public bool Delete() {
136 IntPtr manager = NativeMethods.OpenSCManager(null, null,
137 ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
139 if (manager == IntPtr.Zero)
142 IntPtr service = NativeMethods.OpenService(manager, id,
143 ServiceAccessRights.SERVICE_ALL_ACCESS);
145 if (service == IntPtr.Zero)
148 ServiceStatus status = new ServiceStatus();
149 NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP,
152 NativeMethods.DeleteService(service);
154 NativeMethods.CloseServiceHandle(service);
155 NativeMethods.CloseServiceHandle(manager);
160 private enum ServiceAccessRights : uint {
161 SERVICE_ALL_ACCESS = 0xF01FF
164 private enum ServiceControlManagerAccessRights : uint {
165 SC_MANAGER_ALL_ACCESS = 0xF003F
168 private enum ServiceType : uint {
169 SERVICE_KERNEL_DRIVER = 1,
170 SERVICE_FILE_SYSTEM_DRIVER = 2
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,
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
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
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;
216 private enum FileAccess : uint {
217 GENERIC_READ = 0x80000000,
218 GENERIC_WRITE = 0x40000000
221 private enum CreationDisposition : uint {
226 TRUNCATE_EXISTING = 5
229 private enum FileAttributes : uint {
230 FILE_ATTRIBUTE_NORMAL = 0x80
234 ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
235 ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
237 private static class NativeMethods {
238 private const string ADVAPI = "advapi32.dll";
239 private const string KERNEL = "kernel32.dll";
241 [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
242 public static extern IntPtr OpenSCManager(string machineName,
243 string databaseName, ServiceControlManagerAccessRights dwAccess);
245 [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
246 [return: MarshalAs(UnmanagedType.Bool)]
247 public static extern bool CloseServiceHandle(IntPtr hSCObject);
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);
258 [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
259 SetLastError = true)]
260 public static extern IntPtr OpenService(IntPtr hSCManager,
261 string lpServiceName, ServiceAccessRights dwDesiredAccess);
263 [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
264 SetLastError = true)]
265 [return: MarshalAs(UnmanagedType.Bool)]
266 public static extern bool DeleteService(IntPtr hService);
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);
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);
280 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
281 public static extern bool DeviceIoControl(SafeFileHandle device,
282 IOControlCode ioControlCode,
283 [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer,
285 [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
286 uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
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);