java.lang.Uns พอใจLinkError: ไม่พบโพรซีเดอร์ที่ระบุ

Nov 16 2020

ฉันกำลังพยายามพัฒนา JNA wrapper ของ C ++ DLL

ฉันไม่สามารถเข้าถึงรหัสของ DLL ฉันตรวจสอบ DLL โดยใช้ depend.exe และฉันเห็นว่าไม่มีมัณฑนากรรอบ ๆ วิธีการ C ++ และดูเหมือนว่าextern "C"จะถูกตั้งค่าในไฟล์ C ++ * .h ที่ฉันดึงมา

แต่ฉันมีข้อผิดพลาดต่อไปนี้:

ข้อยกเว้นในเธรด "main" java.lang.Uns SatisfiedLinkError: เกิดข้อผิดพลาดในการค้นหาฟังก์ชัน 'คำนวณ': ไม่พบโพรซีเดอร์ที่ระบุ

ที่ com.sun.jna.Function. (Function.java:252) ที่ com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:600) ที่ com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:576) ที่ com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:562) ที่ com.sun.jna.Library$Handler.invoke(Library.java:243) at com.sun.proxy.$Proxy0.compute (ไม่ทราบแหล่งที่มา) ที่ com.JNA.main (JNA.java:171)

ดูไฟล์ cpp * .h ของฉัน:

#ifdef __cplusplus

extern "C" {

#endif

typedef struct s_mine
{
    e_color           color;    //e_color is enum type made of int values
    his               data;        
    int               str;        
    unsigned int      wild;         
    unsigned int      hello;        
    float             rice; 
} mine;

typedef struct s_his
{
    unsigned char * data; 
    unsigned int    size;
} his;

// compute function which raised the exception

int compute(const his* const input, void ** outputPointer);

// treat function raised also the same exception

int treat(const mine* inputParameter, mine* outputParameter);

#ifdef __cplusplus

}

#endif

ดูด้านล่างกระดาษห่อ JNA ของฉัน:

public interface MyInterface extends Library {

    @FieldOrder({"data", "size"})
    public static class his extends Structure {
        public static class ByReference extends his implements Structure.ByReference {}
        public static class ByValue extends rt_buffer implements Structure.ByValue {}
        public Pointer data;
        public int size;
    }

    @FieldOrder({"color","data","str","wild","hello","rice"})
    public class mine extends Structure {
        public static class ByReference extends mine implements Structure.ByReference {}
        public int color; 
        public his data;
        public int str; 
        public int wild; 
        public int hello; 
        public float rice;
    }

    public int compute(his input, Pointer[] outputPointer);

    public int treat(mine inputParameter, mine outputParameter);
}

ดังนั้นในชั้นเรียนการทดสอบของฉันฉันตั้งค่า:

// COMPUTE

MyInterface.his.ByReference input_ref = new MyInterface.his.ByReference();

ByteBuffer init_buffer;

// init_buffer is initialized with some not null values

Pointer init_p = Native.getDirectBufferPointer(init_buffer);

input_ref.data = init_p;

input_ref.size = init_buffer.capacity();

Pointer[] outputPointer = null;

int resultCompute = compute(input_ref, outputPointer);

// TREAT

MyInterface.mine.ByReference inputParameter_ref = new MyInterface.mine.ByReference();

MyInterface.his.ByValue buffer = new MyInterface.his.ByValue();

// initialize buffer with an input buffer value different from null value

// Set other fields of inputParameter_ref with none null values

inputParameter_ref.data = buffer;

MyInterface.mine.ByReference outputParameter_ref = null;

int resultTreat = treat(inputParameter_ref, outputParameter_ref);

ดังนั้นฉันจึงรู้สึกว่าข้อยกเว้นที่เพิ่มขึ้นไม่ได้มาจากการใช้งานของฉัน แต่มาจาก DLL แต่ฉันไม่มีเงื่อนงำใด ๆ ที่จะอธิบายว่าเหตุใดเกี่ยวกับการยืนยันของฉันในตอนต้นของโพสต์ของฉัน

  1. อาจมีเหตุผลอื่นนอกจากมัณฑนากรและปัญหาการประกาศภายนอกหรือไม่?

  2. ฉันจะตรวจสอบได้อย่างไรว่ามีการตั้งค่าการประกาศภายนอกจากการตรวจสอบ DLL ด้วยขึ้นอยู่กับ.exe

@dbwiddis Thanx สำหรับการตอบกลับของคุณ แต่:

  1. const ของเขา * const อินพุตหมายความว่าอินพุตเป็นตัวชี้ค่าคงที่ในโครงสร้างของเขาคงที่ ซึ่งหมายความว่าตัวชี้เป็นพารามิเตอร์แบบอ่านอย่างเดียวบนค่าแบบอ่านอย่างเดียว

  2. ฉันตั้งค่า outputPointer เป็นอาร์เรย์เพราะฉันไม่แน่ใจเกี่ยวกับวิธีการใช้งาน แน่นอนฉันต้องการมันเป็นพารามิเตอร์อินพุตสำหรับวิธีอื่น สำหรับ c ++ ฉันมีบางอย่างเช่น:

int compute(const his* const input, void ** outputPointer); // **outputPointer is an output of compute method

int manage(void * inputPointer); // As *outputPointer becomes an input of manage method

ดังนั้นฉันจึงมีใน jna Wrapper ของฉัน:

public int compute(his input, Pointer[] outputPointer); public int manage(Pointer inputPointer);

ในชั้นเรียนทดสอบของฉันฉันมี:

Pointer[] outputPointer = null;

int resultCompute = compute(input_ref, outputPointer);

int manage(outputPointer[0]);

อย่างไรก็ตามฉันลองทำตามคำแนะนำของคุณดังนี้: ดังนั้นฉันจึงมีใน jna Wrapper ของฉัน:

public int compute(his input, PointerByReference outputPointer);

public int manage(Pointer inputPointer);

ในชั้นเรียนทดสอบของฉันฉันมี:

PointerByReference outputPointer = null;

int resultCompute = myInterface.compute(input_ref, outputPointer);

int myInterface.manage(outputPointer.getValue());

แต่ฉันยังคงมีปัญหาเดิม เพื่อเป็นการเตือนความจำไม่ว่าวิธีการใดที่กำหนดไว้ใน c ++ dll ฉันมีข้อยกเว้นที่เพิ่มขึ้นเหมือนกัน ฉันรู้สึกจริงๆว่าปัญหาไม่ได้มาจากการใช้งาน jna ของฉัน รายละเอียดที่สำคัญในชั้นทดสอบของฉันฉันทำการอัปโหลด dll:

Map options = new HashMap();

options.put(Library.OPTION_FUNCTION_MAPPER, new StdCallFunctionMapper() {
public String getFunctionName(NativeLibrary library, Method method) {
System.out.println("method names = "+method.getName());
return super.getFunctionName(library, method);
}
});

MyInterface myInterface = (MyInterface) Native.load("dllName",MyInterface.class,options);

sysout ด้านบนแสดงชื่อของเมธอดปัจจุบันซึ่งเรียกว่าเช่น I have method names = computeแสดง การดีบักโค้ดฉันสังเกตเห็นว่ามีปัญหากับชื่อวิธีการ แต่เนื่องจาก sysout แสดงชื่อของเมธอดที่ฉันประกาศใน jna wrapper ของฉันจึงไม่เป็นประโยชน์ ฉันเพิ่งทำการทดสอบอย่างรวดเร็วด้วยวิธีการปลอมซึ่งไม่ได้กำหนดไว้ใน c ++ dll และฉันมีข้อผิดพลาดเดียวกัน: ไม่พบขั้นตอน ดังนั้นฉันคิดว่ามีปัญหากับ dll นั้นจริงๆ แต่ฉันไม่รู้จะหาได้อย่างไร ...

คำตอบ

cknelle Nov 21 2020 at 23:12

สุดท้ายฉันต้องเพิ่มในคลาสหลักของ java Test ซึ่งเรียก wrapper ของฉันในบรรทัดต่อไปนี้เพื่อแก้ปัญหาของฉัน: System.setProperty ("jna.library.path", "C: \ myWrapper \ src \ main \ resources"); โดยที่ C: \ myWrapper \ src \ main \ resources คือโฟลเดอร์ที่เก็บไฟล์ dll ของฉัน

แต่ไม่ได้อธิบายว่าทำไมฉันไม่จำเป็นต้องตั้งค่าบรรทัดนี้สำหรับ dll อื่นที่เก็บไว้ในโฟลเดอร์เดียวกับที่ฉันประกาศ jna.library.path ในตัวแปรสภาพแวดล้อมของฉันด้วย