You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
15 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* ----------------------------------------------------------
* 文件名称HWiNFO.cs
*
* 作者:秦建辉
*
* 微信splashcn
*
* 博客http://www.firstsolver.com/wordpress/
*
* 开发环境:
* Visual Studio V2013
* .NET Framework 4 Client Profile
*
* 版本历史:
* V2.1 2016年12月29日
* 修正硬盘序列号长度为奇数时的处理错误
*
* V2.0 2015年12月04日
* 增加对VMware虚拟机的判断。虚拟机可以伪造任意网卡MAC地址
* 在WDK中实现0权限获取硬盘序列号
*
* V1.0 2014年04月06日
* 实现基于WMI获取网卡原生MAC地址、硬盘序列号、CPU ID
* 实现基于WDK获取网卡原生MAC地址
* 实现结合设备安装类GUID和设备接口类GUID获取设备VIDPID
------------------------------------------------------------ */
using System;
using System.Collections.Generic;
using System.Management;
using System.Runtime.InteropServices;
using System.Text;
namespace POSV.HWiNFO
{
public static partial class HWiNFO
{
/// <summary>
/// 基于WMI获取设备属性值
/// </summary>
/// <param name="QueryIndex">要查询的属性值索引</param>
/// <returns>属性值集合</returns>
/// <remarks>
/// QueryIndex其值含义如下
/// 0网卡原生MAC地址剔除虚拟网卡
/// 1网卡原生MAC地址剔除虚拟网卡和USB网卡
/// 2硬盘序列号
/// 3主板序列号
/// 4CPU ID
/// 5BIOS序列号
/// 6主板型号
/// 7网卡当前MAC地址剔除虚拟网卡
/// 8网卡当前MAC地址剔除虚拟网卡和USB网卡
/// </remarks>
public static string[] WMI_DeviceQuery(int QueryIndex)
{
// 确定查询语句和属性名称
string Command;
string PropertyName;
switch (QueryIndex)
{
case 0: // 网卡原生MAC地址剔除虚拟网卡
Command = "SELECT PNPDeviceID FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))";
PropertyName = "PNPDeviceID";
break;
case 1: // 网卡原生MAC地址剔除虚拟网卡和USB网卡
Command = "SELECT PNPDeviceID FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%')) AND (NOT (PNPDeviceID LIKE 'USB%'))";
PropertyName = "PNPDeviceID";
break;
case 2: // 硬盘序列号
Command = "SELECT SerialNumber FROM Win32_DiskDrive WHERE (SerialNumber IS NOT NULL) AND (MediaType LIKE 'Fixed hard disk%')";
PropertyName = "SerialNumber";
break;
case 3: // 主板序列号
Command = "SELECT SerialNumber FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)";
PropertyName = "SerialNumber";
break;
case 4: // 处理器ID
Command = "SELECT ProcessorId FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)";
PropertyName = "ProcessorId";
break;
case 5: // BIOS序列号
Command = "SELECT SerialNumber FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)";
PropertyName = "SerialNumber";
break;
case 6: // 主板型号
Command = "SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)";
PropertyName = "Product";
break;
case 7: // 网卡当前MAC地址剔除虚拟网卡
Command = "SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))";
PropertyName = "MACAddress";
break;
case 8: // 网卡当前MAC地址剔除虚拟网卡和USB网卡
Command = "SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%')) AND (NOT (PNPDeviceID LIKE 'USB%'))";
PropertyName = "MACAddress";
break;
default:
return null;
}
// 进行WMI查询
List<string> DeviceList = new List<string>(16);
ManagementObjectCollection DevicePropertyCollection = new ManagementObjectSearcher(Command).Get();
if (DevicePropertyCollection != null)
{
foreach (ManagementObject DeviceProperty in DevicePropertyCollection)
{
string Property = (string)DeviceProperty[PropertyName]; // 获取属性值
if (!DeviceList.Contains(Property)) DeviceList.Add(Property); // 去掉重复值
}
}
if (DeviceList.Count == 0) return null;
switch (QueryIndex)
{
case 0: // 网卡原生MAC地址
case 1: // 网卡原生MAC地址剔除USB网卡
for (int i = DeviceList.Count - 1; i >= 0; i--)
{
string PermanentAddress = GetPermanentAddressByDeviceId(DeviceList[i]);
if (PermanentAddress == null)
{ // 移除当前项
DeviceList.RemoveAt(i);
}
else
{ // 替换为网卡原生MAC地址
DeviceList[i] = PermanentAddress;
}
}
break;
case 2: // 硬盘序列号
for (int i = DeviceList.Count - 1; i >= 0; i--)
{
DeviceList[i] = ProcessHardDiskSerialNumber(DeviceList[i]);
}
break;
case 7: // 网卡当前MAC地址
case 8: // 网卡当前MAC地址剔除USB网卡
for (int i = DeviceList.Count - 1; i >= 0; i--)
{ // 去掉冒号
DeviceList[i] = DeviceList[i].Replace(":", "");
}
break;
default:
break;
}
return DeviceList.ToArray();
}
/// <summary>
/// 查看系统中是否存在指定标识的硬件设备
/// </summary>
/// <param name="CPUID">处理器标识,可以为空</param>
/// <param name="HardDiskSerialNumber">硬盘序列号,可以为空</param>
/// <param name="MacAddress">网卡MAC地址已剔除虚拟网卡和USB网卡可以为空</param>
/// <returns>
/// true匹配成功
/// false匹配失败
/// </returns>
/// <remarks>
/// 说明:
/// 对设备标识不区分大小写
/// 空项不做判断,非空项必须全部满足
/// </remarks>
public static bool WMI_DeviceMatch(string CPUID, string HardDiskSerialNumber, string MacAddress)
{
// CPU ID
if (!string.IsNullOrEmpty(CPUID))
{
string[] Properties = WMI_DeviceQuery(4);
if (Properties == null) return false;
bool IsExist = false;
foreach (string Item in Properties)
{
if (CPUID.Equals(Item, StringComparison.OrdinalIgnoreCase))
{
IsExist = true;
break;
}
}
if (!IsExist) return false;
}
// 硬盘序列号
if (!string.IsNullOrEmpty(HardDiskSerialNumber))
{
string[] Properties = WMI_DeviceQuery(2);
if (Properties == null) return false;
bool IsExist = false;
foreach (string Item in Properties)
{
if (HardDiskSerialNumber.Equals(Item, StringComparison.OrdinalIgnoreCase))
{
IsExist = true;
break;
}
}
if (!IsExist) return false;
}
// 网卡原生MAC地址
if (!string.IsNullOrEmpty(MacAddress))
{
string[] Properties = WMI_DeviceQuery(1);
if (Properties == null) return false;
bool IsExist = false;
foreach (string Item in Properties)
{
if (MacAddress.Equals(Item, StringComparison.OrdinalIgnoreCase))
{
IsExist = true;
break;
}
}
if (!IsExist) return false;
}
// 判断程序是否是在VMware虚拟机中运行
if (WMI_IsVMware()) return false; else return true;
}
/// <summary>
/// 输出硬件信息到指定INI文件
/// </summary>
/// <param name="iniFileName">要保存的ini文件名</param>
/// <returns>
/// true成功
/// false失败
/// </returns>
public static bool WMI_DeviceInfoPrint(string iniFileName)
{
if (string.IsNullOrEmpty(iniFileName)) return false;
LINQToINI iniFile = new LINQToINI();
// 网卡原生MAC地址
string[] Properties = WMI_DeviceQuery(1);
if (Properties != null)
{
for (int i = 0; i < Properties.Length; i++)
{
iniFile.WriteProfileString("MacAddress", i.ToString(), Properties[i]);
}
}
// 硬盘序列号
Properties = WMI_DeviceQuery(2);
if (Properties != null)
{
for (int i = 0; i < Properties.Length; i++)
{
iniFile.WriteProfileString("HardDiskSerialNumber", i.ToString(), Properties[i]);
}
}
// CPU ID
Properties = WMI_DeviceQuery(4);
if (Properties != null)
{
for (int i = 0; i < Properties.Length; i++)
{
iniFile.WriteProfileString("CPUID", i.ToString(), Properties[i]);
}
}
iniFile.Save(iniFileName);
return true;
}
/// <summary>
/// 判断程序是否在VMware虚拟机中运行
/// </summary>
/// <returns>
/// true程序是在VMware虚拟机中运行
/// false程序不是在VMware虚拟机中运行
/// </returns>
public static bool WMI_IsVMware()
{
string Command = "SELECT Model FROM Win32_DiskDrive WHERE (MediaType LIKE 'Fixed hard disk%')";
ManagementObjectCollection DevicePropertyCollection = new ManagementObjectSearcher(Command).Get();
if (DevicePropertyCollection != null)
{
foreach (ManagementObject DeviceProperty in DevicePropertyCollection)
{
string Model = (string)DeviceProperty["Model"];
if (!string.IsNullOrEmpty(Model) && (Model.IndexOf("VMware") >= 0))
{
return true;
}
break; // 只需要判断第一个硬盘
}
}
return false;
}
/// <summary>
/// 获取网卡原生物理地址
/// </summary>
/// <param name="PNPDeviceID">设备ID</param>
/// <returns>网卡原生物理地址</returns>
private static string GetPermanentAddressByDeviceId(string PNPDeviceID)
{
// 生成设备路径名
string DevicePath = @"\\.\" + PNPDeviceID.Replace('\\', '#') + "#{ad498944-762f-11d0-8dcb-00c04fc3358c}";
// 获取设备句柄
IntPtr DeviceHandle = Kernel32.CreateFile(DevicePath, NativeFileAccess.SPECIAL, NativeFileShare.FILE_SHARE_READ | NativeFileShare.FILE_SHARE_WRITE, IntPtr.Zero, NativeFileMode.OPEN_EXISTING, IntPtr.Zero, IntPtr.Zero);
if (DeviceHandle != Kernel32.INVALID_HANDLE_VALUE)
{
byte[] ucData = new byte[8];
int nBytesReturned;
// 获取原生MAC地址
const int IOCTL_NDIS_QUERY_GLOBAL_STATS = 0x00170002;
uint OID_802_3_PERMANENT_ADDRESS = 0x01010101;
bool isOK = Kernel32.DeviceIoControl(DeviceHandle, IOCTL_NDIS_QUERY_GLOBAL_STATS, ref OID_802_3_PERMANENT_ADDRESS, Marshal.SizeOf(OID_802_3_PERMANENT_ADDRESS), ucData, ucData.Length, out nBytesReturned, IntPtr.Zero);
Kernel32.CloseHandle(DeviceHandle);
if (isOK)
{
StringBuilder sb = new StringBuilder(nBytesReturned << 1);
for (int i = 0; i < nBytesReturned; i++)
{
sb.Append(ucData[i].ToString("X2"));
}
return sb.ToString();
}
}
return null;
}
/// <summary>
/// 处理硬盘序列号
/// </summary>
/// <param name="SerialNumber">硬盘序列号</param>
/// <returns>处理后的硬盘序列号</returns>
private static string ProcessHardDiskSerialNumber(string SerialNumber)
{
StringBuilder sb;
if (SerialNumber.Length == 40) // InterfaceType = "IDE"
{
sb = new StringBuilder(20);
for (int i = 0; i < 40; i += 2)
{ // 将16进制表示的字符转换为Unicode字符
sb.Append(Convert.ToChar(Convert.ToInt32(SerialNumber.Substring(i, 2), 16)));
}
}
else
{
sb = new StringBuilder(SerialNumber);
}
if (sb.Length % 2 == 0)
{ // 每2个字符互换位置
for (int i = 0; i < sb.Length; i += 2)
{
char ch = sb[i];
sb[i] = sb[i + 1];
sb[i + 1] = ch;
}
}
sb.Replace(" ", ""); // 去掉空格
return sb.ToString();
}
/// <summary>
/// 版权信息
/// </summary>
public static string Copyright { get { return "©秦建辉 http://www.firstsolver.com V20151204R1"; } }
}
}