Java 调用 C# DLL

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

 

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_TestJNI.h文件,javah设置如下, 

 
 

 

3,在Visual Studio 2010新建一个C#项目CSharp(项目类型为Visual C# -->Windows?类库)

编辑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)。

// 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)

#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。

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java调用C语言主要是通过JNI(Java Native Interface)来实现的。JNI是一种Java应用程序与本地代码(如C或C++)进行交互的机制。 首先,需要编写一个C语言的共享库(也称为动态链接库或DLL)。在C代码中,使用`#include <jni.h>`包含JNI的头文件,定义一个`JNIEXPORT`修饰的方法,该方法会在Java中被调用。在这个方法中,可以执行C语言的操作,或者通过调用Java提供的JNI函数来与Java进行交互。 编写完C代码后,需要使用编译器将其编译成共享库文件。在Windows环境下,可以使用命令行运行`gcc -shared -o libexample.dll example.c`命令进行编译。在Linux环境下,可以使用`gcc -shared -o libexample.so example.c`命令进行编译。 在Java代码中,使用`System.loadLibrary()`方法加载已编译的共享库文件。然后,通过`native`关键字将Java方法声明为本地方法。在方法体内部,可以调用C语言的方法。 例如,假设C代码中定义了一个`JNIEXPORT void JNICALL Java_com_example_NativeExample_nativeMethod(JNIEnv *env, jobject obj)`方法,在Java中可以通过以下代码调用该方法: ``` class NativeExample { public native void nativeMethod(); static { System.loadLibrary("example"); } } public class Main { public static void main(String[] args) { NativeExample example = new NativeExample(); example.nativeMethod(); } } ``` 需要注意的是,调用C代码时需要处理好Java和C之间的类型转换和内存管理。JNI提供了一些函数来实现这些功能,如`GetMethodID()`、`CallVoidMethod()`和`GetArrayElements()`等。 总之,Java通过JNI调用C语言主要是通过编写C共享库,并使用JNI函数来与Java进行交互。通过合理使用JNI提供的函数,可以在Java调用C代码并实现更高效的程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值