diff -r 99b6bab765f8 -r 763675f19ff4 Hardware/KernelDriver.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Hardware/KernelDriver.cs Sun Oct 31 22:08:47 2010 +0000 @@ -0,0 +1,300 @@ +/* + + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + The Original Code is the Open Hardware Monitor code. + + The Initial Developer of the Original Code is + Michael Möller . + Portions created by the Initial Developer are Copyright (C) 2010 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + +*/ + +using System; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace OpenHardwareMonitor.Hardware { + internal class KernelDriver { + + private string id; + + private SafeFileHandle device; + + public KernelDriver(string id) { + this.id = id; + } + + public bool Install(string path) { + IntPtr manager = NativeMethods.OpenSCManager(null, null, + ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS); + + if (manager == IntPtr.Zero) + return false; + + IntPtr service = NativeMethods.CreateService(manager, id, id, + ServiceAccessRights.SERVICE_ALL_ACCESS, + ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START, + ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null, + null); + + if (service == IntPtr.Zero) { + if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS) + service = NativeMethods.OpenService(manager, id, + ServiceAccessRights.SERVICE_ALL_ACCESS); + else + return false; + } + + if (!NativeMethods.StartService(service, 0, null)) { + if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING) + return false; + } + + NativeMethods.CloseServiceHandle(service); + NativeMethods.CloseServiceHandle(manager); + + return true; + } + + public bool Open() { + device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id, + FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero, + CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL, + IntPtr.Zero), true); + + if (device.IsInvalid) { + device.Close(); + device.Dispose(); + device = null; + } + + return device != null; + } + + public bool IsOpen { + get { return device != null; } + } + + public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) { + if (device == null) + return false; + + uint bytesReturned; + bool b = NativeMethods.DeviceIoControl(device, ioControlCode, + inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), + null, 0, out bytesReturned, IntPtr.Zero); + return b; + } + + public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer, + ref T outBuffer) + { + if (device == null) + return false; + + object boxedOutBuffer = outBuffer; + uint bytesReturned; + bool b = NativeMethods.DeviceIoControl(device, ioControlCode, + inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), + boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer), + out bytesReturned, IntPtr.Zero); + outBuffer = (T)boxedOutBuffer; + return b; + } + + public void Close() { + if (device != null) { + device.Close(); + device.Dispose(); + device = null; + } + } + + public bool Delete() { + IntPtr manager = NativeMethods.OpenSCManager(null, null, + ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS); + + if (manager == IntPtr.Zero) + return false; + + IntPtr service = NativeMethods.OpenService(manager, id, + ServiceAccessRights.SERVICE_ALL_ACCESS); + + if (service == IntPtr.Zero) + return true; + + ServiceStatus status = new ServiceStatus(); + NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, + ref status); + + NativeMethods.DeleteService(service); + + NativeMethods.CloseServiceHandle(service); + NativeMethods.CloseServiceHandle(manager); + + return true; + } + + private enum ServiceAccessRights : uint { + SERVICE_ALL_ACCESS = 0xF01FF + } + + private enum ServiceControlManagerAccessRights : uint { + SC_MANAGER_ALL_ACCESS = 0xF003F + } + + private enum ServiceType : uint { + SERVICE_KERNEL_DRIVER = 1, + SERVICE_FILE_SYSTEM_DRIVER = 2 + } + + private enum StartType : uint { + SERVICE_BOOT_START = 0, + SERVICE_SYSTEM_START = 1, + SERVICE_AUTO_START = 2, + SERVICE_DEMAND_START = 3, + SERVICE_DISABLED = 4 + } + + private enum ErrorControl : uint { + SERVICE_ERROR_IGNORE = 0, + SERVICE_ERROR_NORMAL = 1, + SERVICE_ERROR_SEVERE = 2, + SERVICE_ERROR_CRITICAL = 3 + } + + private enum ServiceControl : uint { + SERVICE_CONTROL_STOP = 1, + SERVICE_CONTROL_PAUSE = 2, + SERVICE_CONTROL_CONTINUE = 3, + SERVICE_CONTROL_INTERROGATE = 4, + SERVICE_CONTROL_SHUTDOWN = 5, + SERVICE_CONTROL_PARAMCHANGE = 6, + SERVICE_CONTROL_NETBINDADD = 7, + SERVICE_CONTROL_NETBINDREMOVE = 8, + SERVICE_CONTROL_NETBINDENABLE = 9, + SERVICE_CONTROL_NETBINDDISABLE = 10, + SERVICE_CONTROL_DEVICEEVENT = 11, + SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12, + SERVICE_CONTROL_POWEREVENT = 13, + SERVICE_CONTROL_SESSIONCHANGE = 14 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct ServiceStatus { + public uint dwServiceType; + public uint dwCurrentState; + public uint dwControlsAccepted; + public uint dwWin32ExitCode; + public uint dwServiceSpecificExitCode; + public uint dwCheckPoint; + public uint dwWaitHint; + } + + private enum FileAccess : uint { + GENERIC_READ = 0x80000000, + GENERIC_WRITE = 0x40000000 + } + + private enum CreationDisposition : uint { + CREATE_NEW = 1, + CREATE_ALWAYS = 2, + OPEN_EXISTING = 3, + OPEN_ALWAYS = 4, + TRUNCATE_EXISTING = 5 + } + + private enum FileAttributes : uint { + FILE_ATTRIBUTE_NORMAL = 0x80 + } + + private const int + ERROR_SERVICE_EXISTS = unchecked((int)0x80070431), + ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420); + + private static class NativeMethods { + private const string ADVAPI = "advapi32.dll"; + private const string KERNEL = "kernel32.dll"; + + [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr OpenSCManager(string machineName, + string databaseName, ServiceControlManagerAccessRights dwAccess); + + [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseServiceHandle(IntPtr hSCObject); + + [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, + SetLastError = true)] + public static extern IntPtr CreateService(IntPtr hSCManager, + string lpServiceName, string lpDisplayName, + ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType, + StartType dwStartType, ErrorControl dwErrorControl, + string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId, + string lpDependencies, string lpServiceStartName, string lpPassword); + + [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, + SetLastError = true)] + public static extern IntPtr OpenService(IntPtr hSCManager, + string lpServiceName, ServiceAccessRights dwDesiredAccess); + + [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, + SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteService(IntPtr hService); + + [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, + SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool StartService(IntPtr hService, + uint dwNumServiceArgs, string[] lpServiceArgVectors); + + [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, + SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ControlService(IntPtr hService, + ServiceControl dwControl, ref ServiceStatus lpServiceStatus); + + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] + public static extern bool DeviceIoControl(SafeFileHandle device, + IOControlCode ioControlCode, + [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, + uint inBufferSize, + [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer, + uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped); + + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, + SetLastError = true)] + public static extern IntPtr CreateFile(string lpFileName, + FileAccess dwDesiredAccess, uint dwShareMode, + IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, + FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); + } + } +}