Ваш код компилируется отлично.На самом деле вы получаете ошибку linker , а не ошибку .
Из сообщения об ошибке видно, что ваш код C ++ пытается вызвать GetUserNameA()
функция.GetUserName()
- это макрос препроцессора #define
в winbase.h
(который входит в windows.h
), который преобразуется в GetUserNameA()
, когда 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()
требуется строка ввода в измененном UTF-8 формате,Однако GetUserNameA()
выводит формат ANSI (отсюда и название A
), а не в UTF-8, не говоря уже о , измененном UTF-8.В Windows вообще нет понятия модифицированного 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() {}