You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JNI调用已有非托管C/C++ DLL方法?

无需重写DLL,直接调用旧非托管C/C++库的JNI方案

你不需要重新编写C++类或生成新DLL,JNI本身支持直接绑定现有非托管库的导出函数,核心是跳过手动编写JNI桥接代码的步骤,直接映射现有函数到Java native方法。以下是具体实现步骤:

1. 确认目标DLL的函数导出信息

首先得拿到旧DLL里要调用的函数的关键信息:

  • 导出函数名(注意C++的名字修饰:若原函数是extern "C"声明的,导出名是纯函数名;否则会有包含参数类型的修饰名)
  • 函数的返回值类型、参数列表
  • 调用约定(__cdecl、__stdcall等,默认C++是__cdecl,Windows API常用__stdcall)

可以用Windows自带的dumpbin工具查看导出表:

dumpbin /exports your_old.dll

2. 调整Java native方法声明

修改你已有的Java包装类,让native方法的签名严格匹配目标DLL的函数:

  • 方法名要和DLL的导出名一致
  • 参数类型和返回值要对应JNI类型:比如C++的int对应JNI的int,char*对应String或byte[],自定义结构体可通过long传递内存指针

示例:假设旧DLL有一个extern "C"导出的函数:

extern "C" __declspec(dllexport) int calculate(int a, int b);

对应的Java native方法声明:

public class OldDllWrapper {
    static {
        // 后续会替换为加载桥接DLL或直接用JNA加载旧DLL
        System.load("C:\\path\\to\\your_old.dll");
    }

    public native int calculate(int a, int b);
}

3. 动态注册JNI函数(核心步骤)

默认JNI通过生成的头文件函数名(比如Java_OldDllWrapper_calculate)匹配方法,但我们要绑定到旧DLL的calculate函数,需用RegisterNatives API手动注册映射关系,只需写一段极简的C++代码生成小的桥接DLL(并非重写旧DLL):

#include <jni.h>
#include <windows.h>

// 定义旧DLL函数的指针类型
typedef int (*CalculateFunc)(int, int);

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if (vm->GetEnv((void**)&env, JNI_VERSION_1_8) != JNI_OK) {
        return JNI_ERR;
    }

    // 找到Java类
    jclass cls = env->FindClass("OldDllWrapper");
    if (cls == nullptr) {
        return JNI_ERR;
    }

    // 加载旧DLL并获取函数地址
    HMODULE hDll = LoadLibraryA("C:\\path\\to\\your_old.dll");
    if (hDll == nullptr) {
        return JNI_ERR;
    }
    CalculateFunc calculate = (CalculateFunc)GetProcAddress(hDll, "calculate");
    if (calculate == nullptr) {
        FreeLibrary(hDll);
        return JNI_ERR;
    }

    // 注册native方法映射
    JNINativeMethod methods[] = {
        {"calculate", "(II)I", (void*)calculate}
    };
    env->RegisterNatives(cls, methods, sizeof(methods)/sizeof(methods[0]));

    return JNI_VERSION_1_8;
}

将这段代码编译成小DLL(比如jni_bridge.dll),修改Java类的静态块加载这个桥接DLL即可:

static {
    System.load("C:\\path\\to\\jni_bridge.dll");
}

替代方案:用JNA跳过JNI代码

如果连桥接DLL都不想写,可使用JNA(Java Native Access),它直接通过Java代码映射非托管DLL的函数,完全不需要写C++代码,用法和C#的P/Invoke类似:

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface OldDll extends Library {
    OldDll INSTANCE = Native.load("your_old.dll", OldDll.class);

    int calculate(int a, int b);
}

// 调用方式
public class Main {
    public static void main(String[] args) {
        int result = OldDll.INSTANCE.calculate(10, 20);
        System.out.println(result);
    }
}

内容的提问来源于stack exchange,提问作者defa0009

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 16:41:06