简体   繁体   English

JNA:找不到指定的过程

[英]JNA: The specified procedure could not be found

I was trying to learn how JNA works, so I decided to use the spotify API (libspotify 0.0.7). 我试图了解JNA的工作原理,所以我决定使用spotify API(libspotify 0.0.7)。 I managed to load my dll correctly, but then it looks like my code is not finding any of the method defined in the API. 我设法正确加载我的DLL,但后来看起来我的代码没有找到API中定义的任何方法。

Here is my code: 这是我的代码:

My main file: 我的主要档案:

public class Test{
    private static final int SPOTIFY_API_VERSION = 7;
private static final char[] APP_KEY = { /* MY APP KEY HERE */ };

    static{
        System.loadLibrary("libspotify");
    }

    public static void main(String[] args){
    JLibspotify libs = JLibspotify.INSTANCE;

    sp_session mySession = new sp_session();
    sp_session_config cfg = new sp_session_config();
    cfg.api_version = SPOTIFY_API_VERSION;
    cfg.cache_location = "tmp";
    cfg.settings_location = "tmp";
    cfg.application_key = APP_KEY;
    cfg.application_key_size = APP_KEY.length;
    cfg.user_agent = "spshell";
    cfg.callbacks = null;

    libs.sp_session_create(cfg, mySession);
}
}

My Library interface: 我的图书馆界面:

public interface JLibspotify extends Library {  
    JLibspotify INSTANCE = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class);

    // Methods definitions
    sp_error sp_session_create(sp_session_config config, sp_session sess);
}

My sp_session Object (opaque C struct) 我的sp_session对象(不透明的C结构)

public class sp_session extends PointerType{
    public sp_session(Pointer address) {
        super(address);
    }
    public sp_session() {
        super();
    }
}

My sp_session_config object 我的sp_session_config对象

public class sp_session_config extends Structure{
    public int api_version; // The version of the Spotify API your application is compiled with.
    public String cache_location;
    public String settings_location;
    public char[] application_key}; // Your application key.
    public int application_key_size; // The size of the application key in bytes
    public String user_agent;
    public sp_session_callbacks callbacks; // Delivery callbacks for session events. NULL if not interested in any callbacks
    public Pointer userdata; // User supplied data for your application
    public boolean compress_playlists;
    public boolean dont_save_metadata_for_playlists;
    public boolean initially_unload_playlists;
}

My sp_error enum 我的sp_error枚举

public enum sp_error {
    SP_ERROR_OK, 
    SP_ERROR_BAD_API_VERSION, 
    SP_ERROR_API_INITIALIZATION_FAILED, 
    SP_ERROR_TRACK_NOT_PLAYABLE, 
    SP_ERROR_RESOURCE_NOT_LOADED, 
    SP_ERROR_BAD_APPLICATION_KEY, 
    SP_ERROR_BAD_USERNAME_OR_PASSWORD, 
    SP_ERROR_USER_BANNED, 
    SP_ERROR_UNABLE_TO_CONTACT_SERVER, 
    SP_ERROR_CLIENT_TOO_OLD, 
    SP_ERROR_OTHER_PERMANENT, 
    SP_ERROR_BAD_USER_AGENT, 
    SP_ERROR_MISSING_CALLBACK, 
    SP_ERROR_INVALID_INDATA, 
    SP_ERROR_INDEX_OUT_OF_RANGE, 
    SP_ERROR_USER_NEEDS_PREMIUM, 
    SP_ERROR_OTHER_TRANSIENT, 
    SP_ERROR_IS_LOADING, 
    SP_ERROR_NO_STREAM_AVAILABLE, 
    SP_ERROR_PERMISSION_DENIED, 
    SP_ERROR_INBOX_IS_FULL, 
    SP_ERROR_NO_CACHE, 
    SP_ERROR_NO_SUCH_USER
}

My Exception Stack Trace 我的异常堆栈跟踪

Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'sp_session_create': The specified procedure could not be found.

at com.sun.jna.Function.<init>(Function.java:129)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:250)
at com.sun.jna.Library$Handler.invoke(Library.java:191)
at $Proxy0.sp_session_create(Unknown Source)
at com.nbarraille.jspotify.main.Test.main(Test.java:49)

The C++ declaration of the method I'm trying to run 我正在尝试运行的方法的C ++声明

/**
 * Initialize a session. The session returned will be initialized, but you will need
 * to log in before you can perform any other operation
 *
 * Here is a snippet from \c spshell.c:
 * @dontinclude spshell.c
 * @skip config.api_version
 * @until }
 *
 * @param[in]   config    The configuration to use for the session
 * @param[out]  sess      If successful, a new session - otherwise NULL
 *
 * @return                One of the following errors, from ::sp_error
 *                        SP_ERROR_OK
 *                        SP_ERROR_BAD_API_VERSION
 *                        SP_ERROR_BAD_USER_AGENT
 *                        SP_ERROR_BAD_APPLICATION_KEY
 *                        SP_ERROR_API_INITIALIZATION_FAILED
 */
SP_LIBEXPORT(sp_error) sp_session_create(const sp_session_config *config, sp_session **sess);

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). 终于通过使用Dependency Walker打开libspotify.dll找到了解决方案:编译器在方法名称中添加了一些额外信息(下划线前缀和@ 4或@ 8后缀)。

I had to: 我不得不:

  • Create an implementation of FunctionMapper that renamed all my methods according to the real names (available in Dependency Walker) 创建FunctionMapper的实现,根据实名重命名我的所有方法(在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. 如果您无法访问它,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"? 另外,你是否在前面的语句中得到了一个错误,即Java变量“artist”的五行定义?

@technomage 's comment is very helpful. @technomage评论非常有帮助。 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: 只需添加StdCallLibrary.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. 适用于Windows 7 32位,Mac OS 10.13.2,64位Unbuntu Linux 16.04上的JNA 4.5.1。 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. 适用于Mac和Linux,但不适用于Windows 7 32位: 查找函数'foo'时出错:找不到指定的过程。

So I changed my interface: 所以我改变了我的界面:

Foo extends StdCallLibrary {
    void foo();
}

and I tried to load the library with the stdcall specific function mapper: 我尝试使用特定于stdcall的函数映射器加载库:

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 :-( 现在它适用于Windows 7 32位,但不适用于Mac或Linux: 无法识别的调用约定: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! 我认为我需要为每个平台提供不同的代码路径,甚至可以动态地添加LibraryStdCallLibrary接口(与另一个Proxy ),但后来我发现我们可以吃午餐并吃掉它! 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. 我不确定JNA是否指定了这种特殊行为,或者更确切地说是JNA的下一版本可能会发生的幸运事故。 Anyway, it's good enough for me. 无论如何,这对我来说已经足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java + JNA:找不到指定的过程 - Java + JNA : The specified procedure could not be found 使用jna的Windows API:找不到指定的过程 - Windows api using jna: The specified procedure could not be found 使用JNA调用CreateFile会产生UnsatisfiedLinkError:查找函数'CreateFile'时出错:找不到指定的过程 - Calling CreateFile using JNA gives UnsatisfiedLinkError: Error looking up function 'CreateFile': The specified procedure could not be found Java JNA FindWindow()-查找函数&#39;FindWindow&#39;时出错:找不到指定的过程 - Java JNA FindWindow() - Error looking up function 'FindWindow': The specified procedure could not be found JNA:在编译的jar中找不到指定的模块 - JNA: The specified module could not be found in compiled jar UnsatisfiedLinkError:找不到指定的过程 - UnsatisfiedLinkError: The specified procedure could not be found JNA java.lang.UnsatisfiedLinkError和找不到指定的模块 - JNA java.lang.UnsatisfiedLinkError and The specified module could not be found 在 JNA 中加载 DLL 时找不到指定的模块 - Specified module could not being found loading DLL in JNA 查找错误:&#39;&#39;找不到指定的过程 - Error looking up for: '' The specified procedure could not be found JNA-UnsatisfiedLinkError:找不到指定的模块。 (在Cgwin上,Win32) - JNA - UnsatisfiedLinkError: The specified module could not be found. (on Cgwin, Win32)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM