Ho creato un modulo C++ per creare un file di libreria condiviso e quindi chiamarlo da Java usando JNI.Il mio codice dll funziona da un file exe, ma non riesce a caricare da Java loadLibrary
Ho 2 ambienti, Windows e Unix e ho un programma eseguibile in C++ e un programma Java che ricompongo solo per ogni ambiente.
- Quando compilo il mio programma tester.exe in Unix ed eseguirlo con metodi dalla mia biblioteca (.so) funziona benissimo.
- Quando compilo il mio programma Java in Unix e carico la mia libreria (.so) con Java loadLibrary, funziona perfettamente.
Quando compilo il mio programma tester.exe in Windows e lo eseguo utilizzando i metodi dalla mia libreria (.dll) funziona correttamente. Proprio come la versione unix .
Quando compilo il mio programma Java in Windows e carico la mia libreria (.dll) con loadLibrary di Java, fallisce. Dice Tentativo di accedere all'indirizzo non valido .
io non riesco a capire il motivo per cui non funziona con Java loadLibrary durante l'esecuzione in Windows, ma funziona ovunque utilizzando lo stesso codice. Se ritardo caricare una DLL dipendente che utilizza la mia libreria, quindi la mia libreria carica in Java ma non è funzionale. So che esiste un codice specifico che causa il problema con Java che carica la mia libreria, ma non riesco a capire perché il mio exe C++ non abbia problemi con gli stessi metodi e le stesse librerie.
La mia DLL ha 1 metodo esposto che chiama 4 metodi da alcune librerie esistenti. Se commento questi 4 metodi, allora la mia DLL viene caricata in Java bene. So che è qualcosa a che fare con questi metodi da una libreria a cui collego la mia DLL. C'è qualcosa di diverso nel modo in cui Java vede le librerie dipendenti? Ho provato a caricare prima le librerie dipendenti, ma uno dei file DLL che carico causa un errore di ricorsione e lo stack trabocca.
Qualcuno sa come aggirare una DLL che provoca un overflow dello stack da un errore di ricorsione? Ho bisogno dei metodi, ma non riesco a caricarlo con java loadLibrary.
Ecco ulteriori dettagli sui file coinvolti e il messaggio di errore effettivo. Ho aggiunto un DllMain al mio file dll inital solo per vedere cosa carica e quando. Se compilo lo stesso programma (my_plain_dll_to_call_JNI_DLL) come un file exe, tutto funziona correttamente. Se lo compilo e lo carico dal mio programma java ciò accade.
- myJavaProgram, chiama semplicemente System.loadLibrary() per caricare un file di base dll che chiama un metodo nel mio altre dll che contiene il codice JNI.
- my_plain_dll_to_call_JNI_DLL è una dll che ho creato collegandola al mio file di libreria dll solo per testare la dipendenza. Si chiama solo un metodo dall'altra DLL che sta chiamando il codice nativo di cui ho bisogno.
- my_JNI_DLL.ll è un file dll collegato alle librerie C++ esistenti di programmazione a cui è necessario accedere da JNI. Contiene chiamate dirette ai metodi nelle librerie di codice sorgente esistenti.
ho scritto il nome del file che visualizza il testo a fianco di ogni linea per mostrare quale livello l'esecuzione è in.
c:\java myJavaProgram
myJavaProgram: Java Static Method Entry.
myJavaProgram: Java Calling System.loadLibrary(my_plain_dll_to_call_JNI_DLL)
my_JNI_DLL.dll: Entering DllMain
my_JNI_DLL.dll: DLL_PROCESS_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_THREAD_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_THREAD_DETACH
my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_DETACH
myJavaProgram: my_plain_dll_to_call_JNI_DLL Loaded!
myJavaProgram: Java Static Method Exit.
myJavaProgram: Entering Main().
my_plain_dll_to_call_JNI_DLL: In call_my_JNI_DLL_method
my_JNI_DLL.dll: In my_JNI_DLL_method
my_JNI_DLL.dll: Entering my_JNI_DLL_CheckEnvironmentVariables()
my_JNI_DLL.dll: Exiting my_JNI_DLL_CheckEnvironmentVariables
my_JNI_DLL.dll: Calling StartExistingNativeCode.
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (0xc0fb007e), pid=7500, tid=7552
#
# JRE version: 6.0_21-b06
# Java VM: Java HotSpot(TM) Client VM (17.0-b16 mixed mode, sharing windows-x86)
# Problematic frame:
# C [KERNELBASE.dll+0x9673]
#
# An error report file with more information is saved as:
# C:\hs_err_pid7500.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_DETACH
my_JNI_DLL.dll: Entering DllMain
my_JNI_DLL.dll DLL_PROCESS_DETACH
Aggiornamento Ho ridotto la questione una libreria di gestione della memoria collegata da un'altra DLL che il mio programma utilizza. La DLL che usa è sh33w32.dll, si chiama SmartHeap ed è una società chiamata Microquil, penso. Ho la versione 3.3, e quando Java LoadLibrary tenta di caricare quella DLL, fallisce. Non sono sicuro di cosa potrei fare per avere un handle java che carica quella libreria. Deve avere qualcosa a che fare con l'area di memoria a cui può accedere Java, rispetto a ciò che Windows consente a un exe di accedere. L'exe non ha problemi con la libreria SmartHeap, ma Java non mi permetterà di usarlo. Qualche idea o esperienza che si occupa di questo? Ho provato a rimuovere la libreria collegata ricompilando le altre librerie, ma poi le normali chiamate nel codice falliscono che normalmente funzionano.
Ulteriori informazioni che si trovano La funzione che è nel dll che non riesce a caricare in Java è chiamato MemRegisterTask. È da un prodotto chiamato SmartHeap di Microquill. Ecco la documentazione che ho trovato su questa funzione. Penso che questa allocazione di memoria sia ciò che fa sì che java non riesca a caricarlo.
MemRegisterTask inizializza la SmartHeap Library. Sulla maggior parte delle piattaforme, non è necessario chiamare MemRegisterTask perché SmartHeap si inizializza automaticamente quando si effettua la prima chiamata.
SmartHeap mantiene un conteggio dei riferimenti di registrazione per ogni attività o processo. Ogni volta che si chiama MemRegisterTask, questo conteggio dei riferimenti viene incrementato. Se l'ultima chiamata a SmartHeap si verifica prima che l'applicazione sia pronta per la chiusura, è possibile chiamare MemUnregisterTask per terminare SmartHeap. MemUnregisterTask decrementa il conteggio dei riferimenti di registrazione di uno - quando il conteggio è zero, SmartHeap libererà qualsiasi memoria allocata da SmartHeap e lo stato di debug associato all'attività o processo corrente.
Forse pubblicare un codice potrebbe aiutare le persone a vedere di più in questo. Solo un rapido controllo: stai esponendo correttamente la tua DLL a java (es .: http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html#impl) – JScoobyCed
Non sono sicuro di poter pubblicare codice, a causa delle regole di lavoro. Ho analizzato ogni altro errore JNI in cui mi sono imbattuto, quindi sto cercando di capire i concetti per vedere se riesco a capire perché non funziona. Sto esponendo il metodo 1 che il mio programma java utilizza correttamente. Il problema è che la DLL non carica nemmeno in Windows Java, Unix Java funziona bene. – Logan
Sembra che dal messaggio di eccezione sia che i parametri della funzione C++ non siano corretti (inseriti in un tipo diverso dal previsto), oppure il collegamento non viene eseguito correttamente. È possibile che la libreria C++ sia stata compilata con convenzioni di chiamata diverse da quelle fornite da JNI. – Attila