2012-04-05 18 views
16

Tôi đã tạo mô-đun C++ để xây dựng thành tệp thư viện được chia sẻ và sau đó gọi nó từ Java bằng JNI.Mã dll của tôi hoạt động từ tệp exe, nhưng không tải được từ Java loadLibrary

Tôi có 2 môi trường, Windows và Unix và tôi có chương trình thực thi C++ và chương trình Java mà tôi vừa biên dịch lại cho từng môi trường.

  • Khi tôi biên dịch chương trình tester.exe của mình trong Unix và chạy nó bằng phương pháp từ thư viện của tôi (.so) nó hoạt động tốt.
  • Khi tôi biên dịch chương trình Java của mình trong Unix và tải thư viện của tôi (.so) với loadLibrary của Java, nó hoạt động tốt.
  • Khi tôi biên dịch chương trình tester.exe của mình trong Windows và chạy chương trình bằng cách sử dụng phương pháp từ thư viện của tôi (.dll), nó hoạt động tốt. Giống như phiên bản unix .

  • Khi tôi biên dịch chương trình Java của mình trong Windows và tải thư viện của tôi (.dll) bằng thư viện tải của Java thì không thành công. Nó nói rằng Cố gắng truy cập địa chỉ không hợp lệ.

Tôi không thể hiểu tại sao nó sẽ không hoạt động với Thư viện tải Java khi chạy trong Windows, nhưng nó hoạt động ở mọi nơi khác bằng cùng một mã. Nếu tôi trì hoãn tải một DLL phụ thuộc mà thư viện của tôi sử dụng, thì thư viện của tôi tải trong Java nhưng không hoạt động. Tôi biết có mã cụ thể gây ra vấn đề với Java tải thư viện của tôi, nhưng tôi không thể tìm ra lý do tại sao C + + exe của tôi không có vấn đề với các phương pháp và thư viện tương tự.


Dll của tôi có 1 phương pháp được tiếp xúc gọi 4 phương pháp từ một số thư viện hiện có. Nếu tôi nhận xét 4 phương pháp đó, thì dll của tôi sẽ tải trong Java. Tôi biết nó là một cái gì đó để làm với các phương pháp này từ một thư viện dll của tôi liên kết đến. Có cái gì khác với cách Java thấy các thư viện phụ thuộc không? Tôi đã thử tải các thư viện phụ thuộc đầu tiên, nhưng một trong những tập tin dll tôi tải gây ra một lỗi đệ quy và tràn ngăn xếp.

Bất cứ ai biết một cách xung quanh một DLL gây ra tràn ngăn xếp từ lỗi đệ quy? Tôi cần các phương pháp trong đó, nhưng tôi không thể tải nó với java loadLibrary.


Dưới đây là thông tin chi tiết hơn về các tệp liên quan và thông báo lỗi thực tế. Tôi đã thêm một DllMain vào tập tin dll inital của tôi chỉ để xem những gì tải và khi nào. Nếu tôi biên dịch cùng một chương trình đó (my_plain_dll_to_call_JNI_DLL) thành một tệp exe, mọi thứ đều hoạt động tốt. Nếu tôi biên dịch nó và tải nó từ chương trình java của tôi điều này xảy ra.

  • myJavaProgram, chỉ cần gọi System.loadLibrary() để tải tệp .dll cơ bản gọi phương thức trong dll khác của tôi có chứa mã JNI.
  • my_plain_dll_to_call_JNI_DLL là một dll mà tôi đã tạo bằng cách liên kết nó với tệp thư viện dll của tôi chỉ để kiểm tra sự phụ thuộc. Nó chỉ gọi một phương thức từ dll khác đang gọi mã nguồn gốc mà tôi cần.
  • my_JNI_DLL.ll là tệp dll được liên kết với lập trình C++ thư viện mà tôi cần truy cập từ JNI. Nó chứa các cuộc gọi trực tiếp đến các phương thức trong các thư viện mã nguồn hiện có.

tôi đã viết tên tập tin hiển thị văn bản bên trái của mỗi dòng để hiển thị những gì lớp thực hiện là trong.

 

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 
 

Cập nhật tôi đã thu hẹp xuống vấn đề để một thư viện quản lý bộ nhớ được liên kết từ một dll khác mà chương trình của tôi sử dụng. Các dll mà nó sử dụng là sh33w32.dll, nó được gọi là SmartHeap và là bởi một công ty tên là Microquil tôi nghĩ. Tôi có phiên bản 3.3, và khi Java LoadLibrary cố gắng tải dll đó, nó không thành công. Tôi không chắc chắn những gì tôi có thể làm để có java xử lý tải thư viện đó. Nó phải có một cái gì đó để làm với khu vực bộ nhớ mà Java có thể truy cập, so với những gì các cửa sổ cho phép một exe để truy cập. Các exe không có vấn đề với thư viện SmartHeap, nhưng Java sẽ không cho phép tôi sử dụng nó. Bất kỳ ý tưởng hoặc kinh nghiệm đối phó với điều này? Tôi đã cố gắng để loại bỏ các thư viện liên kết bằng cách biên dịch lại các thư viện khác, nhưng sau đó các cuộc gọi bình thường trong mã không bình thường làm việc.


Thông tin bổ sung Tìm thấy Chức năng đó là trong dll mà không tải trong java được gọi MemRegisterTask. Đó là từ một sản phẩm được gọi là SmartHeap bởi Microquill. Đây là tài liệu tôi tìm thấy về chức năng này. Tôi nghĩ rằng việc cấp phát bộ nhớ này là nguyên nhân khiến java không thể tải nó.

MemRegisterTask khởi tạo Thư viện SmartHeap. Trên hầu hết các nền tảng, bạn không cần phải gọi MemRegisterTask vì SmartHeap sẽ tự khởi chạy khi bạn thực hiện cuộc gọi đầu tiên.

SmartHeap duy trì số lượng tham chiếu đăng ký cho từng tác vụ hoặc quy trình. Mỗi lần bạn gọi MemRegisterTask, số tham chiếu này được tăng lên. Nếu cuộc gọi cuối cùng của bạn tới SmartHeap xảy ra trước khi ứng dụng của bạn sẵn sàng chấm dứt, bạn có thể gọi MemUnregisterTask để chấm dứt SmartHeap. MemUnregisterTask giảm số lượng tham chiếu đăng ký một lần - khi số đếm bằng 0, SmartHeap sẽ giải phóng mọi bộ nhớ được phân bổ SmartHeap và trạng thái gỡ lỗi được kết hợp với tác vụ hoặc quy trình hiện tại.

+0

Có thể đăng một số mã sẽ giúp mọi người nhìn thấy nhiều hơn về điều này. Chỉ cần kiểm tra nhanh: bạn đang hiển thị đúng DLL của bạn tới java (ví dụ: http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html#impl) – JScoobyCed

+0

Tôi không chắc mình có thể đăng bài hay không mã, vì quy tắc công việc. Tôi đã làm việc thông qua mọi lỗi JNI khác mà tôi đã gặp phải, vì vậy tôi đang cố gắng hiểu các khái niệm để xem liệu tôi có thể thấy tại sao nó không thành công. Tôi đang vạch trần phương pháp 1 mà chương trình java của tôi sử dụng đúng cách. Vấn đề là dll thậm chí không tải trong Windows Java, Unix Java hoạt động tốt. – Logan

+0

Có vẻ như từ thông báo ngoại lệ hoặc là các paramewters đến hàm C++ là không chính xác (marshalled thành một loại khác với dự kiến), hoặc liên kết không được thực hiện đúng cách. Có thể là thư viện C++ được biên dịch với các quy ước gọi khác nhau so với những gì JNI cung cấp/giả định. – Attila

Trả lời

0

Dường như quy ước hoặc loại kích thước cuộc gọi không khớp với tôi. Mỗi trình biên dịch Windows C có bộ đặc thù riêng của nó, và các tiêu đề Windows JNI giả định (một phiên bản gần đây của) Microsoft Visual C++. Nhìn vào cảnh báo chặt chẽ - mất độ chính xác là dấu hiệu xấu.

Ví dụ: __int64 là đặc trưng của MSVC. Bạn cần phải tìm hiểu tên của loại số nguyên 64 bit trong Borland C và ánh xạ nó là __int64 trước khi bao gồm jni.h.

+0

Loại __int64 trong Borland là LongLong và có vẻ như nó đã được xác định. Đừng nghĩ rằng điều đó sẽ ngăn chặn DLL của tôi tải? Tôi đã thay đổi dll của mình để liên kết động với các dll khác bây giờ, nhưng bây giờ mã không thành công trong java, mặc dù dll sẽ tải trong java. Mã dll tương tự vẫn hoạt động tốt khi được tham chiếu từ tệp exe C++. Nó phải là một cái gì đó với cách Java cho phép truy cập vào bộ nhớ. Tôi không thể tìm thấy bất kỳ thông tin tốt về điều đó. – Logan

+0

Tôi woudl vẫn đề nghị để theo dõi các cảnh báo với nguyên nhân gốc rễ. Ngoài ra, bạn đã thử chạy ứng dụng của mình với -verbose: jni? Trên một JVM khác với HotSpot? –

+0

Tôi đã thử chạy với -verbose: jni, nó chỉ được mã của tôi sau đó không thực hiện các lệnh từ dll tôi cần phải sử dụng. Tôi khá thuyết phục đây là một vấn đề bộ nhớ vào thời điểm này. Có vẻ như một tệp DLL được liên kết này đang cố gắng cấp phát bộ nhớ. Khi java cố gắng tải nó, nó nhận được một lỗi đệ quy và tràn ngăn xếp.Chỉ có 1 phương pháp trong dll này thực sự được sử dụng, nhưng tải nó thổi ngăn xếp. – Logan

1

Mọi thứ hữu ích trong tệp nhật ký hs_err .... Thông thường có một backtrace ngăn xếp vv chỉ ra một cái gì đó.

Cũng cố gắng chạy java.exe (với các tham số chạy thử nghiệm tải nội dung) bên trong trình gỡ lỗi?

Từ theo dõi ở trên có thể thấy tải có vẻ hoạt động tốt (đầu ra theo dõi gợi ý rằng dllentrypoint/dllmain đã được tăng cường đầu ra dấu vết/theo dõi của bạn).

Chuỗi trong tải như sau: dlls phụ thuộc

  1. tải
  2. tải dll tự
  3. gọi các dllentrypoint/DllMain w/quá trình đính kèm

Vì vậy, đây là đã vượt quá tải DLL.

Bạn đã kiểm tra xem bạn có đang sử dụng các runtimes gỡ lỗi/phát hành từ Windows không? Gỡ lỗi có thể xung đột với bản phát hành - Java được phát hành, ví dụ mẫu của bạn có thể giống với bản dựng dll của bạn.

+0

Tôi khá nhiều có tất cả các kết hợp của phát hành và gỡ lỗi mà tôi có thể có thể có. Để tạo một phiên bản phát hành DLL, tôi có phải tắt gỡ lỗi không? Tôi đã đọc về điều này, nhưng không chắc chắn làm thế nào để đi về nó. Tôi đã có thể tải dll của tôi bây giờ bằng cách liên kết động với mã tôi cần, nhưng mã tôi cần phải thực hiện thất bại anyway. Vì vậy, liên kết động vs tĩnh đã không tạo ra sự khác biệt. Tôi cũng đọc về cách sử dụng mảng byte cho bộ nhớ, nhưng không chắc chắn làm thế nào để làm điều đó khi tôi chỉ tải dll để bắt đầu với. – Logan

+0

Tôi đã xem qua các tệp nhật ký hs_err, đọc các bài báo trực tuyến về cách đọc chúng, nhưng không có gì cho thấy là vấn đề. Điều thú vị mặc dù, tôi nghĩ kernelbase.dll đã thất bại, nhưng hôm qua tôi chạy mã của tôi và ném một ngoại lệ con trỏ null từ mã C. Nó tạo ra cùng một bản ghi hs_err mà tôi nhận được khi tôi chạy mã của mình. Khi tôi gõ vào điều này, nó làm cho tôi tự hỏi nếu có thực sự là một null ở đâu đó. Tại sao nó làm việc trong các cửa sổ như một exe mặc dù nếu có một giá trị null? Plus tại sao nó sẽ thất bại trên loadlibrary ... – Logan