我们正在为xidobi串口项目实现一些winapi
方法的一对一映射。 C
方法到java的映射按预期工作,但由于未知原因GetLastError()
被清除。
这是 C-Code :
// CreateFile ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_CreateFile(JNIEnv *env, jobject this,
jstring lpFileName,
jint dwDesiredAccess,
jint dwShareMode,
jint lpSecurityAttributes,
jint dwCreationDisposition,
jint dwFlagsAndAttributes,
jint hTemplateFile) {
const char* fileName = (*env)->GetStringUTFChars(env, lpFileName, NULL);
HANDLE handle = CreateFile(fileName,
dwDesiredAccess,
dwShareMode,
(LPSECURITY_ATTRIBUTES) lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
(HANDLE) hTemplateFile);
(*env)->ReleaseStringUTFChars(env, lpFileName, fileName);
return (jint) handle;
}
// GetLastError ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_GetLastError(JNIEnv *env, jobject this) {
return (jint) GetLastError();
}
在 Java 中,我们像这样调用映射的本机方法:
int handle = os.CreateFile("\\\\.\\" + portName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (handle != INVALID_HANDLE_VALUE)
return handle;
int lastError= os.GetLastError(); //-> sometimes 0 (ERROR_SUCCESS)
我们发现,如果我们在GetLastError()
之后立即在C中调用CreateFile(..)
,则会返回正确的错误代码。由于一对一映射很简单,我们假设JNI或VM调用SetLastError()
本身并清除我们的上一个错误。
我们不想放弃一对一的地图设计,那么我们可以做些什么来解决这个难题呢?
这是一个类似的问题,在这种情况下无效:CreateFile() returns INVALID_HANDLE_VALUE but GetLastError() is ERROR_SUCCESS
答案 0 :(得分:4)
无法保证GetLastError()
无论JVM在您对CreateFile
的本机通话与您对GetLastError
的本机通话之间所做的事情都能生存。因此,您应该在GetLastError
之后立即调用CreateFile
并将值保存在您自己的线程本地插槽中。
然后,GetLastError
的实施将从您存储它的任何地方检索它。
您可能希望将其重命名为LastXidobiError或其中某些内容只会检索由您的库中的调用设置的错误。
// Space to store last error ////////////////////////////////////////////
static DWORD dwTlsIndexLastError = 0;
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
){
switch(fdwReason){
case DLL_PROCESS_ATTACH:
dwTlsIndexLastError = TlsAlloc();
break;
case DLL_PROCESS_DETACH:
TlsFree(dwTlsIndexLastError);
dwTlsIndexLastError = 0;
break;
}
return TRUE;
}
///// Save the last error.
///// Call this function after the "real" function whose error you want to report.
void SaveLastError()
{
TlsSetValue(dsTlsIndexLastError, (LPVOID)(DWORD_PTR)GetLastError());
}
// GetLastError ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_GetLastError(JNIEnv *env, jobject this) {
return (jint) TlsGetValue(dsTlsIndexLastError);
}
// CreateFile ////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL
Java_org_xidobi_OS_CreateFile(JNIEnv *env, jobject this,
jstring lpFileName,
jint dwDesiredAccess,
jint dwShareMode,
jint lpSecurityAttributes,
jint dwCreationDisposition,
jint dwFlagsAndAttributes,
jint hTemplateFile) {
const char* fileName = (*env)->GetStringUTFChars(env, lpFileName, NULL);
HANDLE handle = CreateFile(fileName,
dwDesiredAccess,
dwShareMode,
(LPSECURITY_ATTRIBUTES) lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
(HANDLE) hTemplateFile);
// Save the value of GetLastError for the relevant function
SaveLastError();
(*env)->ReleaseStringUTFChars(env, lpFileName, fileName);
return (jint) handle;
}