你的代码compiles美好的。你实际上得到的是linker错误,不是compiler error.
从错误消息中,您可以看到您的 C++ 代码正在尝试调用GetUserNameA()
功能。GetUserName()
是一个预处理器#define
宏在winbase.h
(包含在windows.h
)决定GetUserNameA()
when UNICODE
没有定义:
WINADVAPI
BOOL
WINAPI
GetUserNameA (
__out_ecount_part_opt(*pcbBuffer, *pcbBuffer) LPSTR lpBuffer,
__inout LPDWORD pcbBuffer
);
WINADVAPI
BOOL
WINAPI
GetUserNameW (
__out_ecount_part_opt(*pcbBuffer, *pcbBuffer) LPWSTR lpBuffer,
__inout LPDWORD pcbBuffer
);
#ifdef UNICODE
#define GetUserName GetUserNameW
#else
#define GetUserName GetUserNameA // <-- HERE!
#endif // !UNICODE
由于没有GetUserNameA()
在 C++ 代码中实现的函数,但至少有一个可用的声明(来自winbase.h
),编译器发出引用的机器代码GetUserNameA()
外部(通过名为__imp_GetUserNameA
)。当编译完成后调用链接器时,链接器输出“未解决”错误,因为它无法找到任何实现GetUserNameA
函数来满足该参考。
GetUserNameA()
是一个 Win32 API 函数,实现于Advapi32.dll
。您需要链接到Advapi32.lib
从编译器的 Windows SDK 中,以便链接器可以找到以下实现GetUserNameA()
.
一种方法是添加一个#pragma comment(lib)
对 C++ 代码的声明,例如:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Advapi32.lib") // <-- add this!
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
char acUserName[100] = {};
DWORD nUserName = sizeof(acUserName);
if (GetUserNameA(acUserName, &nUserName)) {
cout << "User name is " << acUserName << "." << endl;
}
else {
DWORD dwErr = GetLastError();
cout << "Unable to get User name, error " << dwErr << "." << endl;
}
return env->NewStringUTF(acUserName);
}
void main() {}
或者:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
#pragma comment(lib, "Advapi32.lib")
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
DWORD nUserName = 100, dwErr;
std::vector<char> acUserName(nUserName);
do {
if (GetUserNameA(&acUserName[0], &nUserName)) {
cout << "User name is " << &acUserName[0] << "." << endl;
break;
}
dwErr = GetLastError();
if (dwErr != ERROR_INSUFFICIENT_BUFFER) {
cout << "Unable to get the User name, error " << dwErr << "." << endl;
break;
}
acUserName.resize(nUserName);
}
while (true);
return env->NewStringUTF(&acUserName[0]);
}
void main() {}
话虽如此,NewStringUTF()
需要输入字符串modified UTF-8 https://docs.oracle.com/javase/10/docs/api/java/io/DataInput.html#modified-utf-8格式。然而,GetUserNameA()
输出 ANSI 格式(因此A
其名称),而不是 UTF-8,更不用说modifiedUTF-8。 Windows没有这个概念modified完全是UTF-8。仅当用户名中不包含任何非 ASCII 字符时,您的代码才能正常工作。
你的 C++ 代码确实应该调用GetUserNameW()
相反,它以 UTF-16 格式输出。然后你可以使用NewString()
代替NewStringUTF()
(Java 字符串无论如何都使用 UTF-16),例如:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Advapi32.lib")
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
WCHAR acUserName[100];
DWORD nUserName = 100;
if (GetUserNameW(acUserName, &nUserName)) {
--nUserName; // ignore the null terminator
wcout << L"User name is " << acUserName << L"." << endl;
}
else
{
nUserName = 0;
DWORD dwErr = GetLastError();
cout << "Unable to get the User name, error " << dwErr << "." << endl;
}
return env->NewString(reinterpret_cast<jchar*>(acUserName), nUserName);
}
void main() {}
或者:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
#pragma comment(lib, "Advapi32.lib")
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
DWORD nUserName = 100, dwErr;
std::vector<WCHAR> acUserName(nUserName);
do {
if (GetUserNameW(&acUserName[0], &nUserName)) {
--nUserName; // ignore the null terminator
wcout << L"User name is " << &acUserName[0] << L"." << endl;
break;
}
dwErr = GetLastError();
if (dwErr != ERROR_INSUFFICIENT_BUFFER) {
nUserName = 0;
cout << "Unable to get the User name, error " << dwErr << "." << endl;
break;
}
acUserName.resize(nUserName);
}
while (true);
return env->NewString(reinterpret_cast<jchar*>(&acUserName[0]), nUserName);
}
void main() {}