【发布时间】:2013-01-18 10:26:41
【问题描述】:
我们正在为xidobi 串行端口项目实现一些winapi 方法的一对一映射。 C 方法到 java 的映射按预期工作,但由于未知原因,GetLastError() 被清除。
这是C代码:
// 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)
我们发现,如果我们在 C 中在 CreateFile(..) 之后立即调用 GetLastError(),则会返回正确的错误代码。由于一对一的映射非常简单,我们假设 JNI 或 VM 自己调用 SetLastError() 并清除我们的最后一个错误。
我们不想放弃一对一的映射设计,那么我们可以做些什么来解决这个难题呢?
这是一个类似的问题,在这种情况下没有帮助:CreateFile() returns INVALID_HANDLE_VALUE but GetLastError() is ERROR_SUCCESS
【问题讨论】:
-
在 Java_org_xidobi_OS_CreateFile() 中调用 GetLastError() 会有帮助吗? Java_org_xidobi_OS_GetLastError() 将返回保存错误代码的变量。
-
在调用
ReleaseStringUTFChars()之前存储GetLastError()的值,并在调用ReleaseStringUTCChars()之后将其传递给SetLastError()? -
在
CreateFile之后立即调用GetLastError()会破坏我们的一对一映射原则。但是,存储最后一个错误代码在单线程世界中有效,但在多线程环境中无效。每个线程都有自己的错误代码,GetLastError()保证这一点,如果我们将值存储在 C 中,我们必须实现这种行为。 -
@hmjd 我们试了你的方法,
ReleaseStringUTCChars()没有清除错误,清除发生在Java_org_xidobi_OS_CreateFile返回之后,Java_org_xidobi_OS_GetLastError输入之前。
标签: java c winapi java-native-interface