JNA: The specified procedure could not be found

送分小仙女□ 提交于 2019-12-01 21:23:56

I finally found the solution by opening the libspotify.dll with Dependency Walker: The compiler added some extra information to the method name (a underscore prefix and a @4 or @8 suffix).

I had to:

  • Create an implementation of FunctionMapper that renamed all my methods according to the real names (available in Dependency Walker)
  • Instantiate my Library with an instance of this mapper in the options map.
    By the way, I don't have access to the definition of the sp_artist structure in C, I just reconstructed it based on the methods offered by the API, could it be the problem?

If you don't have access to it, neither does JNA. If it's an opaque type, look for functions to create, modify and delete it.

Also, did you get an error on the preceding statement, the five-line definition of the Java variable "artist"?

@technomage's comment is very helpful. Here are the details:

The interface can remain the same for all platforms:

Foo extends Library {
    void foo();
}

Just add the StdCallLibrary.FUNCTION_MAPPER function mapper:

Map<String, ?> options = Collections.singletonMap(
    Library.OPTION_FUNCTION_MAPPER,
    StdCallLibrary.FUNCTION_MAPPER
);
Foo proxy = Native.loadLibrary("foo", Foo.class, options);

Works for me with JNA 4.5.1 on Windows 7 32-bit, Mac OS 10.13.2, Unbuntu Linux 16.04 64-bit. I haven't tested other platforms yet, and I didn't compile the native library myself, so your mileage may vary.


Here are even more details:

Initially, my interface looked like this:

Foo extends Library {
    void foo();
}

and I tried to load the native library like this:

Native.loadLibrary("foo", Foo.class);

Worked on Mac and Linux, but not on Windows 7 32-bit: Error looking up function 'foo': The specified procedure could not be found.

So I changed my interface:

Foo extends StdCallLibrary {
    void foo();
}

and I tried to load the library with the stdcall specific function mapper:

Map<String, ?> options = Collections.singletonMap(
    Library.OPTION_FUNCTION_MAPPER,
    StdCallLibrary.FUNCTION_MAPPER
);
Foo proxy = Native.loadLibrary("foo", Foo.class, options);

Now it worked on Windows 7 32-bit, but not on Mac or Linux: Unrecognized calling convention: 63 :-(

I thought I'd need a different code path for each platform, maybe even add the Library or StdCallLibrary interface dynamically (with another Proxy), but then I found that we can have our lunch and eat it too! See above.

I'm not sure though if this particular behavior is specified by JNA or rather a lucky accident that may change with the next release of JNA. Anyway, it's good enough for me.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!