入职一家新公司,面试前完全不知道是用C#开发的,也太底层了,JAVA开发的我,顿时觉得回到五年前,好多配置,一点也不轻便,感觉很笨重,组件全部是手写,但是还好,最底层的组件可以一直使用,就好比是JAVA的JPA组件一样,但是没办法了,已经入职了,由于要开发一个新系统,我不想写权限,也不想写C#,所以就研究了一下JAVA如何调用C#的方法。
在网上知道了有JNA这个组件后,就开始参考网上很多大神写的,让我研究了好几天,在这里做一个积累和总结。我用的是VisualStudio2019和Rider。
顺序是C#生成DLL----------》C++生成DLL----------》JAVA调用
之后的选择X64平台,需要根据自身的开发环境所调整,我的电脑和JDK均是64位
C#
创建一个类库DLL项目,这里不做过多解释,创建就可以了,我用的是Rider创建的,有兴趣的可以自行学习,这里不做介绍。
创建好之后如下图。
然后需要对类库进行设置,右键属性,
- 会有此页面,我这里由于版本太高,默认是4.7.2,所以需要修改成目标框架设置成4,根据自身坏境情况做修改。
- 点击程序集,选择弹出框的COM可见。
- 点击生成选项,目标平台我这里是64,输出路径根据自身情况做调整,勾选选择COM互操作注册。
- 在cs文件中写你需要的测试方法,这里就不过多写了,最基础的代码。
强调一下,方法名跟什么大小写,下划线_都没有任何关系,我在别的文章中看到过,这里做一下解释,只要方法名能对应上即可
记得要保存!
最后一步,右键生成DLL,生成的位置就是上图的输出路径位置。
这第一阶段的C#就好了。
C++
右键解决方案,添加新项目,Windows桌面向导
就会出现Project1,项目名可以自定义,这里不解释了。
右键属性,这里的平台设置需要和之前的C#的目标平台设置一致,在高级中找到公共语言,选择/clr的就可以,老版本开发工具不在高级里,在常规选项里,多留意一下。
继续选择C/C++语言,将符合模式选成否,应该是生成是报错,所以这里需要设置一下,回忆不起来了。
这一套设置完以后,可以开始写代码了。
- 先引用C#的DLL,右键添加引用即可。
- 在源文件上右键添加新项
这里也可以将之后源文件的代码分开成一个头文件,由于我是初级学C的,就不这么麻烦,直接在cpp中完成了,不再单独引用头文件
- 写cpp代码内容。
#ifdef AKL_API
#else
#define AKL_API extern "C" _declspec(dllimport) //交给客户端使用时
#endif
//这里就是对外的JAVA可访问的接口,和大小写,下划线没有任何关系,一致就行
AKL_API int GETADD(int a); //添加函数声明
AKL_API char* getStringInfo(char* str);
//如果这里报错,就说明没有正确引用C#的DLL,看是不是环境问题,一定要注意。
using namespace System;
using namespace ClassLibrary1;
int GETADD(int a)
{
Class1^ method = gcnew Class1();
int result = method->getAddInt(a);
return result;
}
char* getStringInfo(char* str)
{
String^ paraStr = gcnew String(str);
Class1^ method = gcnew Class1();
String^ resultString = method->getStringInfo(paraStr);
char* result = (char*)(void*)System::Runtime::InteropServices::Marshal::StringToCoTaskMemAnsi(resultString);
return result;
}
最后将C++生成DLL。
JAVA代码
JAVA相对来说就很简单了,需要引入JNA的maven包。
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.5.0</version>
</dependency>
--------------两个引用一个就可以,5.5.0版本的会提示方法过时,所以我用的是4.1.0-----------
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.1.0</version>
</dependency>
将C++的DLL文件放在resources目录下
然后将C#的DLL文件放在JDK的bin路径下
public interface JNATest extends Library {
JNATest INSTANCE = (JNATest) Native.loadLibrary("Project1", JNATest.class);
//C++刚才对外的接口名称,需要一致
int GETADD(int a);
String getStringInfo(String a);
}
//导入不导入都可以,不导入直接使用JNATest.INSTANCE
@Autowired
private static JNATest jnaTest;
public static void main(String[] args) {
JNATest clib = jnaTest.INSTANCE;
String resStr = clib.getStringInfo("Akl:Hello!");
System.out.println(resStr);
int resCal = clib.GETADD(101);
System.out.println(resCal);
}
控制台就可以输出了