首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java 读取 Windows 设备的唯一性标识及定位

Java 读取 Windows 设备的唯一性标识及定位

原创
作者头像
Yeats_Liao
发布2025-01-08 09:37:02
发布2025-01-08 09:37:02
1.1K0
举报

在 Windows 系统中,获取设备唯一性标识及定位信息对设备管理、安全监控等场景意义重大。本文介绍 Java 中几种实现方法,如 JNA 库、WMI4Java 库及通过 JNI 结合 Windows API。

1. 使用 JNA 库读取 DEVPKEY_Device_ContainerId

在 Windows 系统中,DEVPKEY_Device_ContainerId是获取设备容器唯一标识符的属性键。设备容器含多个相关设备,此标识符可区分不同设备集合。Java 无直接获取该属性的方法,可借助 JNA (Java Native Access)库访问 Windows 底层接口实现读取。

  1. 引入 JNA 库

若用 Maven 管理项目,在pom.xml添加如下依赖。

代码语言:xml
复制
     <dependency>
         <groupId>net.java.dev.jna</groupId>
         <artifactId>jna</artifactId>
         <version>5.13.0</version>
     </dependency>
  1. 代码示例

以下是读取DEVPKEY_Device_ContainerId的示例代码。代码中的{设备容器路径}要换成实际在注册表中的路径(类似{数字和字母组合},可查看 Windows 注册表确定)。此代码用Advapi32Util类的registryGetStringValue方法从注册表读取指定键值对应的字符串值,访问HKEY_LOCAL_MACHINE下特定路径获取DEVPKEY_Device_ContainerId对应的设备容器唯一标识符。

代码语言:java
复制
     import com.sun.jna.platform.win32.Advapi32Util;
     import com.sun.jna.platform.win32.WinReg;

     public class WindowsDeviceIdReader {
         public static void main(String[] args) {
             String containerId = Advapi32Util.registryGetStringValue(
                     WinReg.HKEY_LOCAL_MACHINE,
                     "SYSTEM\\CurrentControlSet\\Control\\DeviceContainers\\{设备容器路径}\\Properties",
                     "{DEVPKEY_Device_ContainerId}"
             );
             System.out.println("设备容器ID: " + containerId);
         }
     }

2. 使用 WMI4Java 库通过 WMI 读取设备信息

Windows Management Instrumentation(WMI)是微软管理技术,可供管理员和开发者统一查询与管理 Windows 系统资源,包括硬件设备、软件组件等。WMI4Java 库为 Java 程序访问 WMI 提供便捷途径。

  1. 添加依赖

若用 Maven 管理项目,在pom.xml添加如下依赖。

代码语言:xml
复制
     <dependency>
         <groupId>org.boris.winrun4j</groupId>
         <artifactId>wmi4java</artifactId>
         <version>1.5.0</version>
     </dependency>
  1. 代码示例

先创建“WMI”对象,获取“Win32_PhysicalMedia”类实例,该类含物理设备(如硬盘)信息,遍历可获设备序列号这一唯一性标识。不同设备类(如“Win32_NetworkAdapter”用于网络适配器)能提供不同设备标识信息。

代码语言:java
复制
     import org.boris.winrun4j.wmi.WMI;
     import org.boris.winrun4j.wmi.WMIException;
     import org.boris.winrun4j.wmi.WMIClass;
     import org.boris.winrun4j.wmi.WMIObject;

     public class WMIDeviceIdReader {
         public static void main(String[] args) {
             try {
                 WMI wmi = new WMI();
                 // 查询Win32_PhysicalMedia类获取设备信息
                 WMIClass c = wmi.getWMIClass("Win32_PhysicalMedia");
                 for (WMIObject o : c.instances()) {
                     String serialNumber = o.get("SerialNumber").toString();
                     System.out.println("设备序列号(唯一性标识之一): " + serialNumber);
                 }
             } catch (WMIException e) {
                 e.printStackTrace();
             }
         }
     }

3. 使用 Java 本地接口(JNI)结合 Windows API

JNI 允许 Java 代码与其他语言(如 C/C++)编写的代码交互。Windows 提供了一系列 API 用于获取设备信息,例如SetupDiGetDeviceInstanceId函数可获取设备实例 ID,这是设备的一种唯一性标识。

  1. 编写 C/C++代码

C++获取设备实例 ID 示例。代码先通过SetupDiGetClassDevs获取设备信息集,再用SetupDiEnumDeviceInfoSetupDiGetDeviceInstanceId获取首个设备实例 ID 存于传入缓冲区。

代码语言:cpp
复制
     #include <windows.h>
     #include <setupapi.h>
     #include <stdio.h>

     extern "C" {
         __declspec(dllexport) void getDeviceInstanceId(char* buffer, DWORD bufferSize) {
             HDEVINFO deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT);
             if (deviceInfoSet == INVALID_HANDLE_VALUE) {
                 return;
             }
             SP_DEVINFO_DATA deviceInfoData;
             deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
             if (SetupDiEnumDeviceInfo(deviceInfoSet, 0, &deviceInfoData)) {
                 DWORD requiredSize;
                 SetupDiGetDeviceInstanceId(deviceInfoSet, &deviceInfoData, buffer, bufferSize, &requiredSize);
             }
             SetupDiDestroyDeviceInfoList(deviceInfoSet);
         }
     }
  1. 编译为动态链接库(DLL)

使用 Visual C++编译器时,可在命令行执行cl /LD getDeviceInstanceId.cpp(代码存于该文件)进行编译,编译步骤因编译器而异。

  1. 在 Java 中调用 DLL

Java 示例代码:用System.loadLibrary加载编译好的 DLL,定义本地方法getDeviceInstanceId,在main方法中调用该方法获取设备实例 ID,注意替换yourDLLName为实际 DLL 名称。

代码语言:java
复制
     class DeviceIdJNI {
         static {
             System.loadLibrary("yourDLLName"); // 替换为实际的DLL名称
         }
         public native void getDeviceInstanceId(byte[] buffer, int bufferSize);

         public static void main(String[] args) {
             DeviceIdJNI deviceIdJNI = new DeviceIdJNI();
             byte[] buffer = new byte[1024];
             deviceIdJNI.getDeviceInstanceId(buffer, buffer.length);
             String deviceInstanceId = new String(buffer).trim();
             System.out.println("设备实例ID: " + deviceInstanceId);
         }
     }

4. 总结

  • JNA 库便捷但受限特定属性读取。
  • WMI4Java 库简单但受 WMI 限制且性能可能不足。
  • JNI 结合 Windows API 能灵活获取底层设备信息,但编写维护复杂且要求开发者了解 Windows API 和 C/C++编程。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 使用 JNA 库读取 DEVPKEY_Device_ContainerId
  • 2. 使用 WMI4Java 库通过 WMI 读取设备信息
  • 3. 使用 Java 本地接口(JNI)结合 Windows API
  • 4. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档