JNI 调用,C++ invoke C# dll return to java(见git代码)
2016-03-16 00:00
701 查看
摘要: javah;dll;c#;
Java无法直接调用C# dll,需要通过经过桥接的方式,进行中继转发一下请求。查阅大量资料,做了大量实验,不停的调试、排错之后,期间试过jni4net,不过这个插件需要 修改原有的C# DLL内容,还会生成一些额外的Java代码,jni4net侵入性太多,将它排除。最后通过管理性的C++桥接方式,成功完成了Java调用C# DLL。
国内很多文章都是只有文章,没有在文中附上完整的代码工程,导致读者做实验时非常麻烦。而老外经常会带上完整的代码工程,这让读者做实验时参考起来非常方便。本文附上完整的Java、C++、CSharp代码工程,供大家参考。
实验环境:
64位 Win 7
jdk1.7.0_51
Eclipse 4.3.1
Visual Studio 2010
具体的实现步骤如下:
1,新建一个Java项目TestJNI,定义一个Java客户端类 TestJNI.java
Java代码
package msg;
public class TestJNI {
public native boolean MasSentMessage(String a, String b);
public native int add(int a, int b);
public native String submit(String a, String b);
public native boolean testBoolean(String a, String b);
static {
System.loadLibrary("CPP");
}
public static void main(String[] args) {
TestJNI t = new TestJNI();
// System.out.println(t.MasSentMessage("user", "pass"));
// System.out.println(t.add(2, 20));
System.err.println(t.submit("user", "pass"));
// System.err.println(t.testBoolean("1", "pass"));
}
}
2,调用JDK里的javah命令通过TestJNI.java类生成msg_TestJ
3ff0
NI.h文件,javah设置如下,
3,在Visual Studio 2010新建一个C#项目CSharp(项目类型为Visual C# -->Windows?类库)
编辑C#文件如下:
C#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OJMain
{
public class OJEntrance
{
private int result;
public int Result
{
get { return result + 10; }
set { this.result = value; }
}
public string submit(string str1, string str2)
{
Console.WriteLine("成功调用了dll");
return "CSharp:" + str1 + ":" + str2;
}
public bool testBoolean(string str1, string str2)
{
if (str1.Equals("true"))
{
return true;
}
else
{
return false;
}
}
}
}
4,利用Visual Studio 2010 生成dll。
如果调用C#项目的Java客户端在64位的机器上,需要重新生成dll,在Visual Studio 2010的生成参数设置如下,将目标平台设为“Any CPU”
5,在Visual Studio 2010中新建一个win32 dll模式的C++项目CPP,为了在Java和C#之间的调用建立通道并进行转接。
5.1设置两个项目属性
一,项目属性-->配置属性--> 常规:“公共语言运行时支持”设为“公共语言运行时支持(/clr)”
二,项目属性-->配置属性-->C/C++-->代码生成:“运行库”设为“多线程DLL(/MD)”
5.2 C++源文件的目录里放置如下内容:
JDK目录里的两个h文件(jni.h,jni_md.h);
Java项目中生成的msg_TestJNI.h;
C#项目CSharp中生成的CSharp.dll ;
5.3编写jstring 和 string的相互转换功能,完整代码参见附件 CPP.rar(CPP.cpp)。
Cpp代码
// char* To jstring
jstring stringTojstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}
// jstring To char*
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
// jstring To String
String^ jstringToStr(JNIEnv* env, jstring jstr)
{
char* str = jstringTostring(env, jstr);
String^ value = gcnew String(str);
free(str);
return value;
}
// String To jstring
jstring strTojstring(JNIEnv* env, String^ rtn)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(rtn);
size_t convertedChars = 0;
size_t sizeInBytes = ((rtn->Length + 1) * 2);
char *ch = (char *)malloc(sizeInBytes);
errno_t err = wcstombs_s(&convertedChars,
ch, sizeInBytes,
wch, sizeInBytes);
jstring js = stringTojstring(env, ch);
free(ch);
return js;
}
5.4 编写C++的管理类, 完整代码参见附件 CPP.rar(CPP.cpp)
Cpp代码
#include "jni.h"
#include "jni_md.h"
#include "msg_TestJNI.h"
//引入c#的库和命名空间
#using "CSharp.dll"
using namespace OJMain;
……
…..
JNIEXPORT jint JNICALL Java_msg_TestJNI_add
(JNIEnv *env, jobject obj, jint a, jint b)
{
//c#中的对象
OJEntrance ^o = gcnew OJEntrance();
o->Result = a + b;
return o->Result;
}
JNIEXPORT jstring JNICALL Java_msg_TestJNI_submit
(JNIEnv *env, jobject obj, jstring str1, jstring str2)
{
//c#中的对象
OJEntrance ^o = gcnew OJEntrance();
return strTojstring(env, o->submit(jstringToStr(env,str1), jstringToStr(env,str2)));
}
JNIEXPORT jboolean JNICALL Java_msg_TestJNI_testBoolean
(JNIEnv *env, jobject obj, jstring str1, jstring str2)
{
//c#中的对象
OJEntrance ^o = gcnew OJEntrance();
return o->testBoolean(jstringToStr(env,str1), jstringToStr(env,str2));
}
5.5利用Visual Studio 2010生成CPP.dll
6,JDK的bin目录里放置如下内容
C# 项目CSharp中生成的CSharp.dll ;
C++项目CPP中生成的CPP.dll;
7,在Java项目TestJNI中 运行TestJNI,调用C# dll。
在没装VS得虚拟机上重现issue,解决方法是VS2010编译C++的DLL时去掉/MD选项:
修改DLL工程属性:
property:
Configuration: Active(Release) Platform Active(x64)
C/C++ -> Code Generation -> Runtime Library
将 Multi-threaded DLL (/MD)去掉,留空白
重新编译DLL,不用装VS2010测试通过。
记得先复制.h文件到项目根目录,然后再添加现有项,不然会出现找不到jni.h和XXXX.h的情况
Java无法直接调用C# dll,需要通过经过桥接的方式,进行中继转发一下请求。查阅大量资料,做了大量实验,不停的调试、排错之后,期间试过jni4net,不过这个插件需要 修改原有的C# DLL内容,还会生成一些额外的Java代码,jni4net侵入性太多,将它排除。最后通过管理性的C++桥接方式,成功完成了Java调用C# DLL。
国内很多文章都是只有文章,没有在文中附上完整的代码工程,导致读者做实验时非常麻烦。而老外经常会带上完整的代码工程,这让读者做实验时参考起来非常方便。本文附上完整的Java、C++、CSharp代码工程,供大家参考。
实验环境:
64位 Win 7
jdk1.7.0_51
Eclipse 4.3.1
Visual Studio 2010
具体的实现步骤如下:
1,新建一个Java项目TestJNI,定义一个Java客户端类 TestJNI.java
Java代码
package msg;
public class TestJNI {
public native boolean MasSentMessage(String a, String b);
public native int add(int a, int b);
public native String submit(String a, String b);
public native boolean testBoolean(String a, String b);
static {
System.loadLibrary("CPP");
}
public static void main(String[] args) {
TestJNI t = new TestJNI();
// System.out.println(t.MasSentMessage("user", "pass"));
// System.out.println(t.add(2, 20));
System.err.println(t.submit("user", "pass"));
// System.err.println(t.testBoolean("1", "pass"));
}
}
2,调用JDK里的javah命令通过TestJNI.java类生成msg_TestJ
3ff0
NI.h文件,javah设置如下,
3,在Visual Studio 2010新建一个C#项目CSharp(项目类型为Visual C# -->Windows?类库)
编辑C#文件如下:
C#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OJMain
{
public class OJEntrance
{
private int result;
public int Result
{
get { return result + 10; }
set { this.result = value; }
}
public string submit(string str1, string str2)
{
Console.WriteLine("成功调用了dll");
return "CSharp:" + str1 + ":" + str2;
}
public bool testBoolean(string str1, string str2)
{
if (str1.Equals("true"))
{
return true;
}
else
{
return false;
}
}
}
}
4,利用Visual Studio 2010 生成dll。
如果调用C#项目的Java客户端在64位的机器上,需要重新生成dll,在Visual Studio 2010的生成参数设置如下,将目标平台设为“Any CPU”
5,在Visual Studio 2010中新建一个win32 dll模式的C++项目CPP,为了在Java和C#之间的调用建立通道并进行转接。
5.1设置两个项目属性
一,项目属性-->配置属性--> 常规:“公共语言运行时支持”设为“公共语言运行时支持(/clr)”
二,项目属性-->配置属性-->C/C++-->代码生成:“运行库”设为“多线程DLL(/MD)”
5.2 C++源文件的目录里放置如下内容:
JDK目录里的两个h文件(jni.h,jni_md.h);
Java项目中生成的msg_TestJNI.h;
C#项目CSharp中生成的CSharp.dll ;
5.3编写jstring 和 string的相互转换功能,完整代码参见附件 CPP.rar(CPP.cpp)。
Cpp代码
// char* To jstring
jstring stringTojstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}
// jstring To char*
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
// jstring To String
String^ jstringToStr(JNIEnv* env, jstring jstr)
{
char* str = jstringTostring(env, jstr);
String^ value = gcnew String(str);
free(str);
return value;
}
// String To jstring
jstring strTojstring(JNIEnv* env, String^ rtn)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(rtn);
size_t convertedChars = 0;
size_t sizeInBytes = ((rtn->Length + 1) * 2);
char *ch = (char *)malloc(sizeInBytes);
errno_t err = wcstombs_s(&convertedChars,
ch, sizeInBytes,
wch, sizeInBytes);
jstring js = stringTojstring(env, ch);
free(ch);
return js;
}
5.4 编写C++的管理类, 完整代码参见附件 CPP.rar(CPP.cpp)
Cpp代码
#include "jni.h"
#include "jni_md.h"
#include "msg_TestJNI.h"
//引入c#的库和命名空间
#using "CSharp.dll"
using namespace OJMain;
……
…..
JNIEXPORT jint JNICALL Java_msg_TestJNI_add
(JNIEnv *env, jobject obj, jint a, jint b)
{
//c#中的对象
OJEntrance ^o = gcnew OJEntrance();
o->Result = a + b;
return o->Result;
}
JNIEXPORT jstring JNICALL Java_msg_TestJNI_submit
(JNIEnv *env, jobject obj, jstring str1, jstring str2)
{
//c#中的对象
OJEntrance ^o = gcnew OJEntrance();
return strTojstring(env, o->submit(jstringToStr(env,str1), jstringToStr(env,str2)));
}
JNIEXPORT jboolean JNICALL Java_msg_TestJNI_testBoolean
(JNIEnv *env, jobject obj, jstring str1, jstring str2)
{
//c#中的对象
OJEntrance ^o = gcnew OJEntrance();
return o->testBoolean(jstringToStr(env,str1), jstringToStr(env,str2));
}
5.5利用Visual Studio 2010生成CPP.dll
6,JDK的bin目录里放置如下内容
C# 项目CSharp中生成的CSharp.dll ;
C++项目CPP中生成的CPP.dll;
7,在Java项目TestJNI中 运行TestJNI,调用C# dll。
JNI java.lang.UnsatisfiedLinkError Can't find dependent libraries解决
java使用C++得DLL,DLL是使用VS2010编译,在本机上测试通过,但测试人员测试时报java.lang.UnsatisfiedLinkError Can't find dependent libraries,这里说明,库得路径都是对得,不必纠缠与找不到库路径。测试同事装了VS2010后issue消失。在没装VS得虚拟机上重现issue,解决方法是VS2010编译C++的DLL时去掉/MD选项:
修改DLL工程属性:
property:
Configuration: Active(Release) Platform Active(x64)
C/C++ -> Code Generation -> Runtime Library
将 Multi-threaded DLL (/MD)去掉,留空白
重新编译DLL,不用装VS2010测试通过。
记得先复制.h文件到项目根目录,然后再添加现有项,不然会出现找不到jni.h和XXXX.h的情况
相关文章推荐
- halcon与C#混合编程(一)打开一张图片
- C#中??操作符和?操作符
- C#高级编程 (第六版) 学习 第四章:继承
- C#开源项目大全
- C#机房重构——DataGridView控件
- C# 泛型约束
- C#机房重构——万事开头难(二)
- C#中数组、ArrayList和List三者的区别
- 4000 代码行统计工具(C#)
- C# 托管资源和非托管资源
- C#版三层登录
- C#中两个窗口怎么传递参数?或者怎么使用另一个窗口的控件呢?
- c# get{}set{}
- C#基础之反射
- C#知识点-反射
- C#基础
- 简单工厂模式(设计模式02)
- C#中IList<>和List<>的区别小结
- c#FileStream文件读写
- c#调试遇到的问题