如何基于JNI实现Java调用C++获取Windows当前用户名?
嘿,我来帮你把已有的JNI Hello World和Windows用户名获取代码整合起来,完成这个PoC。下面是完整的实现步骤和代码,跟着走就能轻松搞定:
1. 编写Java Native接口类
先创建一个Java类,声明我们需要的native方法,同时负责加载后续编译的动态链接库:
public class WindowsUsername { // 声明native方法,用于获取Windows用户名 public native String getWindowsUsername(); // 加载动态链接库 static { System.loadLibrary("WindowsUsernameImpl"); } // 测试主函数 public static void main(String[] args) { WindowsUsername usernameGetter = new WindowsUsername(); String username = usernameGetter.getWindowsUsername(); System.out.println("当前Windows用户名:" + username); } }
2. 生成JNI头文件
用Java的javac命令生成对应的JNI头文件。打开命令行,进入Java类所在目录,执行:
javac -h . WindowsUsername.java
执行后会生成一个名为WindowsUsername.h的头文件,内容大概是这样的:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class WindowsUsername */ #ifndef _Included_WindowsUsername #define _Included_WindowsUsername #ifdef __cplusplus extern "C" { #endif /* * Class: WindowsUsername * Method: getWindowsUsername * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_WindowsUsername_getWindowsUsername (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
3. 实现C++ Native方法
现在把你那部分获取用户名的C++代码和JNI的实现结合起来,创建一个WindowsUsernameImpl.cpp文件:
#include "WindowsUsername.h" #include <windows.h> #include <string> JNIEXPORT jstring JNICALL Java_WindowsUsername_getWindowsUsername (JNIEnv* env, jobject obj) { // 定义缓冲区,Windows用户名最长不超过256字符(含终止符) WCHAR usernameBuffer[256]; DWORD bufferSize = sizeof(usernameBuffer) / sizeof(WCHAR); // 调用Windows API获取用户名 if (GetUserNameW(usernameBuffer, &bufferSize)) { // 将宽字符串转换为JNI的jstring return env->NewString(usernameBuffer, wcslen(usernameBuffer)); } else { // 如果获取失败,返回错误信息 return env->NewStringUTF("获取用户名失败"); } }
这里用了GetUserNameW(宽字符版本),因为JNI的字符串处理默认是Unicode编码,这样能更好地支持包含中文、特殊字符的用户名,避免乱码问题。
4. 编译C++代码为DLL
接下来需要把C++代码编译成Windows动态链接库(.dll文件)。如果你用的是Visual Studio的编译器(cl.exe),可以执行以下命令:
cl /LD /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" WindowsUsernameImpl.cpp
/LD参数表示编译为动态链接库/I参数指定JNI头文件的路径,%JAVA_HOME%是你的Java安装目录,比如C:\Program Files\Java\jdk1.8.0_301
编译成功后会生成WindowsUsernameImpl.dll文件。
5. 运行Java程序
最后运行Java程序,确保DLL文件和Java类在同一个目录,或者通过-Djava.library.path指定DLL的路径:
java -Djava.library.path=. WindowsUsername
正常情况下,你会看到输出当前登录的Windows用户名。
一些关键注意事项
- 确保编译C++代码时的位数(32位/64位)和你的Java版本完全一致,否则会出现加载库失败的错误
- JNI函数名必须和头文件里生成的完全一致,哪怕一个下划线错了,Java都找不到对应的native方法
- 如果你用的是MinGW编译器,编译命令会略有不同,比如:
g++ -shared -o WindowsUsernameImpl.dll -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" WindowsUsernameImpl.cpp
内容的提问来源于stack exchange,提问作者Arka Mallick




