JNI中使用mingw 生成dll。但java调用中出现错误 Exception in thread "main" java.lang.UnsatisfiedLinkEr

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI中使用mingw 生成dll。但java调用中出现错误 Exception in thread "main" java.lang.UnsatisfiedLinkEr相关的知识,希望对你有一定的参考价值。

vc6就可以。java -Djava.library.path=. Test

基本用法在后面给你加上了
MinGW是指只用自由软件来生成纯粹的Win32可执行文件的编译环境,它是Minimalist GNU on Windows的略称。详情请参考<>。
这里的“纯粹”是指「使用msvcrt.dll的应用程序」。无法使用MFC (Microsoft Foundation Classes)。
MinGW:一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你生成本地的Windows程序而不需要第三方C运行时库。
MinGW,即 Minimalist GNU For Windows。它是一些头文件和端口库的集合,该集合允许人们在没有第三方动态链接库的情况下使用 GCC(GNU Compiler C)产生 Windows32 程序。
在基本层,MinGW 是一组包含文件和端口库,其功能是允许控制台模式的程序使用微软的标准C运行时间库(MSVCRT.DLL),该库在所有的 NT OS 上有效,在所有的 Windows 95 发行版以上的 Windows OS 有效,使用基本运行时间,你可以使用 GCC 写控制台模式的符合美国标准化组织(ANSI)程序,可以使用微软提供的 C 运行时间扩展。该功能是 Windows32 API 不具备的。下一个组成部分是 w32api 包,它是一组可以使用 Windows32 API 的包含文件和端口库。与基本运行时间相结合,就可以有充分的权利既使用 CRT(C Runtime)又使用 Windows32 API 功能。
MinGW 官方网站为
实际上 MinGW 并不是一个 C/C++ 编译器,而是一套 GNU 工具集合。除开 GCC (GNU 编译器集合) 以外,MinGW 还包含有一些其他的 GNU 程序开发工具 (比如 gawk bison 等等)。
开发 MinGW 是为了那些不喜欢工作在 Linux(FreeBSD) 操作系统而留在 Windows 的人提供一套符合 GNU 的 GNU 工作环境。
(此前的 cygwin 虽然也是 GNU 的 Windows 移植,但是 cygwin 是有版权的,而不是 GNU。)
所以,使用 MinGW 我们就可以像在 Linux 下一样使用 GNU 程序开发工具。
GCC 就是 MinGW 的核心所在,GCC 是一套支持众多计算机程序语言的编译系统,而且在语言标准的实现上是最接近于标准的。并且 GCC 几乎可以移植到目前所有可用的计算机平台。(我的电脑上就还装有 DevKitPro,里面包含 GCC 的 ARM(for GBA/DS/GP32) 和 MIPS(for PSP) 版本。)
GCC 本身不像 VC 那样拥有 IDE 界面(在 Windows 上也存在 Dev C++ 之类的支持 MinGW 编译器的 IDE)。源代码编辑你可以选用任何你喜欢的文本编辑器(据说微软的开发人员包括 VC 的开发都不用 VC 所带的 IDE 编辑器,而是选用 GNU 的 VIM 编辑器)。然后使用 make 等工具来进行软件项目的编译、链接、打包乃至发布。而像 cvs(svn) 源代码版本控制工具可以让世界上任何一个角落的人都可以参与到软件项目中来。
关于 MFC,微软基础库类,这个随 VC++ 携带的一个源代码公开的开发包,和其他 Windows 程序开发包是一样的。如果有 VC++ 的授权,你完全可以使用 MFC 的源代码,也就是你使用 GCC 来编译 MFC 程序是完全可以的。
当然,GNU 下也很多 Windows 程序开发包,甚至有一些是支持跨平台使用的。不仅仅可以直接把源代码编译为 Windows 程序,也可以不经修改编译为其他操作系统的图形程序。
不过 GNU 下,最流行的图形界面开发库是 GTK+。GTK+ 也能很好的运行在 Windows 平台(比如 GIMP 和 Gaim)。
总体说来,使用 MinGW 就是 GNU。

基本用法:
在mingw环境中生成和使用dll都是十分方便的。
1.生成dll
gcc(g++) -shared -o test.dll test.c(test.cpp)
通过该命令生成test.dll,将导出test.c中非静态的函数和相关的类。

(注by asper:该命令行在处理jni涉及的dll时无效)
我使用微软C++编译器,cl命令对带有空格的路径也是无效的,需要用""括住

2.连接dll到exe中
mingw使用dll的方式和静态库.a的方式是一样的,连接的时候只需要加上-ltest即可,没有lib前缀的要求。
3.编写jni调用的dll
有办法了! 是gcc少了行参数。 如下:
gcc -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 -Wl,--add-stdcall-alias -shared -o call.dll call.c
参数:-Wl,--add-stdcall-alias 可以为函数加上标准调用前缀(stdcall @nn)。
这样编译出的dll就可以了。都知道win32中dll中的函数要求有标准调用前缀,在JNI中不方便手动处理这个,Sun又没说清楚这事由编译器办。所以搞得我很郁闷。找了大半个月,终于在一个很古老的网页上找到答案。

基本上和VC的界面差不多 学习C语言用的最多的还是VC++ 6.0

如果对您有帮助,请记得采纳为满意答案,谢谢!祝您生活愉快!

vaela
参考技术A 那可能是命令不全引起的,我的也是这样。
我在Linux下的JNI也出现这样的问题,找到最后是命令少了一项,多试试。

如何使用 JNI 从 JAVA 调用带有 C++ 参数的函数?

【中文标题】如何使用 JNI 从 JAVA 调用带有 C++ 参数的函数?【英文标题】:How to call a function with arguments in C++ from JAVA using JNI? 【发布时间】:2015-04-14 14:08:47 【问题描述】:

我正在搞这个任务一段时间......

我正在尝试从 java 调用 C# DLL 方法。

我使用this 作为教程,它建议构建一个中间 c++ dll。但是它使用了没有参数的方法,我担心它需要修改才能使用带参数的方法。这是因为当我在 java 中调用 t.SetCounter0("aaa") 函数时出现 unsatisfiedlinkerror 异常。

这是java代码:

package jniTester;

import java.io.Console;

public class Test1 

static 
    //System.load("c:\\Users\\ttene\\Documents\\Visual Studio 2012\\Projects\\CPM\\CPMPerformanceCountersController\\x64\\Debug\\CppWrapperDll.dll");
    System.load("c:\\Users\\ttene\\Documents\\Cpm2Java\\CppWrapperDll.dll");


public native void SetCounter0(String x);

public static void main(String[] args) 

    try 
        Test1 t = new Test1();
        System.out.println("1");
        t.SetCounter0("aaa");
        System.out.println("2");

     catch (Exception e) 
        e.printStackTrace();
    

这是cpp:

#include <jni.h>
#include <iostream>

#include "Java\jnicall.h"
#include "MCPP\CppWrapperDll.h"

JNIEXPORT void JNICALL Java_Test1_SetCounter0  (JNIEnv *jn, jobject jobj) 

    std::cout << "Java_Test1_SetCounter0";

    // Instantiate the MC++ class.
    CppWrapperDllC* t = new CppWrapperDllC();

    // The actual call is made. 
    t->callCountersControl();

这是h文件:

#using <mscorlib.dll>
#using "CountersControl.netmodule"

using namespace System;

public __gc class CppWrapperDllC

    public:
        // Provide .NET interop and garbage collecting to the pointer.
        CountersControl __gc *t;

        CppWrapperDllC() 

            t = new CountersControl();
            // Assign the reference a new instance of the object
        

    // This inline function is called from the C++ Code
    void callCountersControl() 

        t->SetCounter0("aaa");
    
;

最后这是 jni h 文件:

#include <jni.h>
/* Header for class Test1 */

#ifndef _Included_Test1
#define _Included_Test1
#ifdef __cplusplus
extern "C" 
#endif
/*
 * Class:     Test1
 * Method:    SetCounter0
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_Test1_SetCounter0(JNIEnv *, jobject);

#ifdef __cplusplus

#endif
#endif

感谢您的帮助。谢谢。

【问题讨论】:

>尝试编译项目 Wink | ;) 它不起作用?当然,谁知道 jni.h 在哪里?顺便说一句,您应该知道 jni.h 对 Java-C# 交互选项有很大帮助,阅读更多材料 Wink | ;) 添加包含目录:项目 -> 属性 -> 配置属性 -> VC++ 目录 -> 包含目录 -> 添加 2 个文件夹“%your jdk%/include”和“%your jdk%/include/win32” 似乎更好(微笑),编译库时有一些小错误,但我认为google会帮助你。将 C++ 项目构建到 HelloWorld.dll 中,然后将 HelloWorld.dll 和 CSharpHelloWorld.netmodule 复制到 D:\。运行 Test1.class 看看发生了什么。 ...取自这篇教程。 我的提示:尝试另一个教程,例如this 似乎更准确/详细。 亲爱的 xerx593,我也尝试了您建议的教程。我现在不尝试调用 C# dll,而只调用 C++ dll。结果是一样的: Exception in thread "main" java.lang.UnsatisfiedLinkError: Test1.SetCounter0([C)V at Test1.SetCounter0(Native Method) at Test1.main(Test1.java:17) The jni signature was changed到 JNIEXPORT void JNICALL Java_Test1_SetCounter0 (JNIEnv *, jobject, jcharArray) 因为我现在发送 char 数组。我希望我可以向您发送短代码 sn-ps,以便您查看它们。谢谢 【参考方案1】:

您应该使用 javah 创建 JNI 标头。如果你使用过它,标题中的声明实际上应该是这样的:

JNIEXPORT void JNICALL Java_Test1_SetCounter0(JNIEnv *, jobject, jstring);

其中 jstring 是作为参数传递给 SetCounter0(...) 的字符串。

【讨论】:

谢谢保罗。我做了你提供的,它确实将 jstring 添加到签名中。不,我得到:C:\Users\tten\Documents\Cpm2Java>java Test1 1 Java_Test1_SetCounter0# # Java 运行时环境检测到致命错误:## 内部错误 (0xe0434352),pid=3340,tid=5060 ## JRE 版本:Java(TM) SE Runtime Environment (8.0_31-b13) (build 1.8.0_31-b13) # Java VM: Java HotSpot(TM) 64-Bit Server VM (25.31-b07 混合模式 windows-amd64 压缩 oops) # 有问题的框架:# C [KERNELBASE.dll+0x940d]... 顺便说一句,我不得不从文件中删除这个包,因为我不能用它执行 javah。我试过: javah -verbose -jni -classpath 。 jniTester.Test1 但它返回:错误:找不到“jniTester.Test1”的类文件。我不明白为什么。所以我删除了包装并且它工作了。 对于打包问题:我使用 ant,所以我没有从命令行使用 javah 的任何经验。对于错误,这可能会有所帮助:***.com/questions/24244288/… 好吧,如你所见,我没有使用任何 Marshaling 方法,因此本文不相关。保罗,你还有什么想法吗?谢谢。 好吧,错误代码本身只说明 .NET 出现了一些问题。但是如果没有日志和完整的错误消息,我无法说出更具体的内容。更改 JNI-header 后是否重新编译了 dll 和 javacode。这个问题可能是由于一些不正确的方法名。不过只是猜测。

以上是关于JNI中使用mingw 生成dll。但java调用中出现错误 Exception in thread "main" java.lang.UnsatisfiedLinkEr的主要内容,如果未能解决你的问题,请参考以下文章

JNI调用C语言

JNI使用方法

我可以在 Java 中控制 JNI 本机方法调用名称吗?

Java调用DLL

eclipse如何开发并调用dll文件

java使用JNA框架调用dll动态库