2012-04-05 13 views
16

Utworzyłem moduł C++, aby utworzyć plik biblioteki współużytkowanej, a następnie wywołać go z poziomu Javy przy użyciu JNI.Mój kod dll działa z pliku exe, ale nie ładuje się z biblioteki Java loadLibrary

Mam 2 środowiska, Windows i Unix i mam program wykonywalny C++ oraz program Java, który właśnie rekompiluję dla każdego środowiska.

  • Kiedy skompilować mój program tester.exe w Unix i uruchomić go za pomocą metod z mojej biblioteki (.so) to działa dobrze.
  • Gdy kompiluję mój program Java w systemie Unix i ładuję moją bibliotekę (.so) za pomocą loadLibrary Java, to działa dobrze.
  • Gdy kompiluję mój program tester.exe w systemie Windows i uruchamiam go przy użyciu metod z mojej biblioteki (.dll), to działa dobrze. Podobnie jak wersja unix .

  • Kiedy kompiluję mój program Java w Windows i ładuję moją bibliotekę (.dll) z loadLibrary Java, to się nie powiedzie. Mówi Próba dostępu do nieprawidłowego adresu .

Nie mogę zrozumieć, dlaczego nie będzie działać z Java LoadLibrary podczas pracy w systemie Windows, ale działa wszędzie przy użyciu tego samego kodu. Jeśli opóźniam ładowanie zależnej biblioteki DLL, z której korzysta moja biblioteka, to moja biblioteka ładuje się w Javie, ale nie działa. Wiem, że istnieje specjalny kod, który powoduje problem z ładowaniem biblioteki Java przez java, ale nie mogę zrozumieć, dlaczego mój C++ exe nie ma problemu z tymi samymi metodami i bibliotekami.


Moja biblioteka dll ma jedną odsłoniętą metodę, która wywołuje 4 metody z niektórych istniejących bibliotek. Jeśli skomentuję te 4 metody, moja biblioteka dll ładuje się w Javie dobrze. Wiem, że to ma coś wspólnego z tymi metodami z biblioteki, do której prowadzi moja biblioteka DLL. Czy jest coś innego w tym, w jaki sposób Java widzi biblioteki zależne? Próbowałem najpierw ładować zależne biblioteki, ale jeden z ładowanych plików dll powoduje błąd rekursji i przepełnienie stosu.

Ktoś wie, jak obejść bibliotekę DLL, która powoduje przepełnienie stosu spowodowane błędem rekursji? Potrzebuję metod w nim, ale nie mogę załadować go z loadLibrary java.


Oto więcej informacji o plikach i faktycznym komunikacie o błędzie. Dodałem DllMain do mojego podstawowego pliku dll po prostu zobaczyć, co ładuje i kiedy. Jeśli skompiluję ten sam program (my_plain_dll_to_call_JNI_DLL) jako plik exe, wszystko działa poprawnie. Jeśli go skompiluję i załaduję z mojego programu java, to się stanie.

  • myJavaProgram, po prostu wywołuje System.loadLibrary(), aby załadować podstawową .dll plik, który wywołuje metodę w moim innych dll, który zawiera kod JNI.
  • my_plain_dll_to_call_JNI_DLL to dll, który utworzyłem, łącząc go z moim plikiem biblioteki DLL tylko po to, aby przetestować zależność. Po prostu wywołuje metodę z innej biblioteki dll, która wywołuje natywny kod, którego potrzebuję.
  • my_JNI_DLL.ll to plik DLL połączony z istniejącymi bibliotekami programowania w języku C++ , które muszę uzyskać dostęp z JNI. Zawiera bezpośrednie wywołania metod w istniejących bibliotekach kodu źródłowego.

napisałem nazwę pliku Wyświetlanie tekstu na lewo od każdej linii, aby pokazać, co warstwa wykonanie jest.

 

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 
 

Aktualizacja mam zawężony do problemu biblioteka zarządzania pamięcią, która jest połączona z inną biblioteką dll, z której korzysta mój program. Plik DLL, którego używa, jest sh33w32.dll, nazywa się SmartHeap i jest przez firmę o nazwie Microquil, jak sądzę. Mam wersję 3.3, a gdy Java LoadLibrary próbuje załadować dll, nie powiedzie się. Nie jestem pewien, co mogę zrobić, aby uchwyt Java ładowanie tej biblioteki. Musi mieć coś wspólnego z obszarem pamięci, do którego może mieć dostęp Java, w przeciwieństwie do tego, do których okien umożliwia dostęp exe. Exe nie ma problemu z biblioteką SmartHeap, ale Java nie pozwoli mi jej używać. Wszelkie pomysły lub doświadczenia dotyczące tego? Próbowałem usunąć połączoną bibliotekę, rekompilując inne biblioteki, ale normalnie działają normalne wywołania w kodzie.


Dodatkowe informacje Znaleziony funkcji, która jest w dll, że nie można załadować w java nazywa MemRegisterTask. To produkt SmartHeap firmy Microquill. Oto dokumentacja, którą znalazłem na temat tej funkcji. Myślę, że ta alokacja pamięci powoduje, że java nie może go załadować.

Narzędzie MemRegisterTask inicjuje bibliotekę SmartHeap. Na większości platform nie trzeba wywoływać funkcji MemRegisterTask, ponieważ SmartHeap zainicjuje się podczas pierwszego połączenia.

SmartHeap utrzymuje liczbę referencyjną rejestracji dla każdego zadania lub procesu. Za każdym razem, gdy wywołujesz funkcję MemRegisterTask, ta liczba odwołań jest zwiększana. Jeśli Twoje ostatnie połączenie z SmartHeap nastąpi przed zakończeniem twojej aplikacji, możesz zadzwonić do MemUnregisterTask, aby zakończyć SmartHeap. MemUnregisterTask zmniejsza liczbę odwołań do rejestracji o jeden - gdy liczba wynosi zero, SmartHeap zwolni pamięć przydzieloną przez SmartHeap i stan debugowania powiązany z bieżącym zadaniem lub procesem.

+0

Może opublikowanie kodu pomoże ludziom zobaczyć więcej na ten temat. Tylko szybkie sprawdzenie: poprawnie ujawniasz swoją bibliotekę DLL na java (np .: http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html#impl) – JScoobyCed

+0

Nie jestem pewien, czy mogę publikować kod, ze względu na reguły pracy. Pracowałem nad każdym innym błędem JNI, na który natknąłem się, więc staram się zrozumieć pojęcia, aby zobaczyć, czy nie widzę powodu, dla którego to się nie udaje. Ujawniam metodę 1, którą mój program java używa poprawnie. Problem polega na tym, że biblioteka dll nie ładuje się nawet w systemie Windows Java, Unix Java działa dobrze. – Logan

+0

Wygląda na to, że z komunikatu o wyjątku wynika, że ​​albo parametry paramter do funkcji C++ są niepoprawne (zestawione w inny typ, niż oczekiwano), albo połączenie nie zostanie wykonane poprawnie. Możliwe, że biblioteka C++ została skompilowana z różnymi konwencjami wywołania niż to, co zapewnia/zakłada JNI. – Attila

Odpowiedz

0

Wygląda na to, że do mnie nie podoba się konwencja wywoływania lub niedopasowanie rozmiaru. Każdy kompilator Windows C ma własny zestaw osobliwości, a nagłówki Windows JNI zakładają (najnowszą wersję) Microsoft Visual C++. Przyjrzyj się dokładnie ostrzeżeniom - utrata precyzji jest złym sygnałem. Na przykład: __int64 jest specyficzny dla MSVC. Musisz dowiedzieć się, jaka jest nazwa 64-bitowego typu integer w Borland C i zamapuj go na __int64, zanim włączysz jni.h.

+0

Typ __int64 w Borland ma format LongLong i wygląda na zdefiniowany. Czy uważasz, że to uniemożliwiłoby załadowanie biblioteki DLL? Zmieniłem moją bibliotekę dll, aby dynamicznie linkować do innych bibliotek dll teraz, ale teraz kod kończy się niepowodzeniem w java, mimo że dll załaduje się w java. Ten sam kod dll działa dobrze nadal, gdy odwołuje się z pliku exe C++. To musi być coś, jak Java pozwala na dostęp do pamięci. Po prostu nie mogę znaleźć żadnych dobrych informacji na ten temat. – Logan

+0

W dalszym ciągu sugeruję śledzenie ostrzeżeń do głównej przyczyny. Czy próbowałeś też uruchomić swoją aplikację za pomocą polecenia -verbose: jni? W JVM innym niż HotSpot? –

+0

Próbowałem uruchomić z -verbose: jni, to po prostu dostaje się do mojego kodu, a następnie nie wykonuje poleceń, które są z biblioteki DLL, której potrzebuję użyć. Jestem przekonany, że jest to kwestia pamięci w tym momencie. Wygląda na to, że ta jedna biblioteka DLL, która jest połączona, próbuje przydzielić pamięć. Kiedy java próbuje go załadować, otrzymuje błąd rekursji i przepełnienie stosu.Jest tylko jedna metoda w tej bibliotece dll, która faktycznie jest używana, ale ładowanie jej powoduje dmuchanie stosu. – Logan

1

Wszystko, co jest przydatne w pliku dziennika hs_err .... Zwykle istnieje ślad cofnięcia stosu itp. wskazując coś.

Próbowano również uruchomić java.exe (z parametrami uruchamiającymi test, który ładuje rzeczy) wewnątrz debuggera w wersji ?

Z powyższego śledzenia widać, że ładowanie działa dobrze (wynik śledzenia sugeruje, że , że dllentrypoint/dllmain zostało rozszerzone przez użytkownika w/trace).

Sequence w załadunku jest następujący: DLL zależnych

  1. obciążenia
  2. sama
  3. zadzwoń dllentrypoint/DllMain w/proces dołączyć

dll

  • obciążenie to więc już poza załadunku biblioteka DLL.

    Czy sprawdziłeś, czy używasz środowiska wykonawczego debugowania/wydania z systemu Windows? Debugowanie może kolidować z wersją - Java jest wersją, twój przykładowy exe prawdopodobnie był taki sam jak twoja biblioteka dll.

  • +0

    Mam prawie wszystkie kombinacje wersji i debugowania, które mógłbym mieć. Aby wydać wersję DLL, czy muszę wyłączyć debugowanie? Czytałem o tym, ale nie byłem pewien, jak to zrobić. Byłem w stanie załadować moją bibliotekę dll teraz dynamicznie łącząc się z potrzebnym kodem, ale kod, który muszę wykonać, i tak się nie powiedzie. Tak więc połączenie dynamiczne z statycznym nie miało znaczenia. Czytałem również o użyciu tablic bajtów dla pamięci, ale nie jestem pewien, jak to zrobić, gdy po prostu ładowanie biblioteki dll na początek. – Logan

    +0

    Przeszedłem przez pliki dziennika hs_err, przeczytałem artykuły online, jak je czytać, ale nic nie wskazywało na problem. Interesujące jest jednak, że myślałem, że kernelbase.dll zawodzi, ale wczoraj uruchomiłem mój kod i wyrzuciłem wyjątek wskaźnika zerowego z kodu C. Stworzyła ten sam dziennik hs_err, który otrzymuję, gdy uruchomię mój kod. Kiedy to piszę, zastanawiam się, czy naprawdę gdzieś jest null. Dlaczego miałby działać w oknach jako exe, jeśli istnieje wartość pusta? Plus dlaczego miałoby to zawieść na loadlibrary ... – Logan

    Powiązane problemy