2

xidobiシリアルポートプロジェクトwinapiのために、いくつかのメソッドの1対1のマッピングを実装しています。メソッドのJavaへのマッピングは期待どおりに機能しますが、不明な理由でクリアされます。CGetLastError()

これが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)

We figured out that if we call GetLastError() in C right after CreateFile(..) the correct error code is returned. Since the one-to-one mapping is dead simple we assume that JNI or the VM calls SetLastError() itself and clears our last error.

We don't want to give up the one-to-one mapping design, so what can we do to solve this puzzle?

Here is a similar question that doesn't help in this case: CreateFile() returns INVALID_HANDLE_VALUE but GetLastError() is ERROR_SUCCESS

4

1 に答える 1

4

へのネイティブGetLastError()呼び出しと へのネイティブ呼び出しの間で JVM が何を行っていても、 が生き残るという保証はありません。したがって、すぐにafterを呼び出して、独自のスレッド ローカル スロットに値を保存する必要があります。CreateFileGetLastErrorGetLastErrorCreateFile

次に、の実装は、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;
}
于 2013-01-18T13:27:31.760 に答える