Java调用C#编写的DLL

目录

1.编写DLL

1.1新建项目(Visual Studio)

 1.2编写测试用例

 1.3生成解决方案,导出DLL

 1.4第一次生成解决方案时报错的处理办法

 2.本地注册DLL

2.1下载jacob-1.18(下载地址如下)

2.2将jacob-1.18-x64.dll放到C:\Windows\System32文件夹下

 2.3注册自己写的组件

 3.java调用

3.1pom.xml引入jar包

3.2程序调用

 4.记录调用dll时的报错及解决办法

4.1com.jacob.com.ComFailException: Can't map name to dispid

4.2com.jacob.com.ComFailException: Can't co-create object

4.3com.jacob.com.ComFailException: Can't get object clsid from progid

1.编写DLL

1.1新建项目(Visual Studio)

 

 1.2编写测试用例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyTest
{
    public class TestClass
    {
        /**
         * public TestClass()测试用例 传入两个整数,返回两个整数之和
         * 此方法不能用static修饰,不然在java端调用时会报错
         * com.jacob.com.ComFailException: Can't map name to dispid:sum
         */
        public int sum(int a, int b) {
            int tem = a + b;
            return tem;
        }
    }
}

 1.3生成解决方案,导出DLL

以下设置必须要有,不然会在注册dll的时候不提示“成功注册了类型”

 生成-生成解决方案

 1.4第一次生成解决方案时报错的处理办法

1.4.1出现“无法注册程序集dll- 拒绝访问。请确保您正在以管理员身份运行应用程序。对注册表项的访问被拒绝

WIN+R,运行对话框中输入gpedit.msc,开启组策略

在“计算机配置”-“Windows 设置”-“安全设置”-“本地策略”-“安全选项”-找到右侧的
“用户账户控制:以管理员批准模式运行所有管理员”这个项,把它设成禁用

 2.本地注册DLL

2.1下载jacob-1.18(下载地址如下)

https://github.com/freemansoft/jacob-project/releases/tag/Root_B-1_18

​​​​​​​

2.2将jacob-1.18-x64.dll放到C:\Windows\System32文件夹下

 2.3注册自己写的组件

2.3.1将步骤1生成的dll放到 D:\java\dll(目录自己随意,我的是这个目录) 

2.3.2 用管理员身份打开命令提示符

2.3.3在cmd中跳转到C:\Windows\Microsoft.NET\Framework64下版本最高的framework版本下

cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319

2.3.4注册DLL

Regasm D:\java\dll\MyTest.dll /tlb:D:\java\dll\MyTest.tlb

如果提示下边这个(即只提示成功导出,不提示成功注册),说明导出的dll没有根据步骤1.3导出设置进行设置

 2.3.4将导出的DLL放到jdk的bin目录下

 每个人的jdk安装目录不一样,放到自己的安装目录下即可

C:\Program Files\Java\jdk1.8.0_144\bin

 3.java调用

3.1pom.xml引入jar包

<dependency>
    <groupId>com.hynnet</groupId>
    <artifactId>jacob</artifactId>
    <version>1.18</version>
</dependency>

3.2程序调用

package cn.main.xx;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

/**
 * TODO
 * @author Mengwx
 * @version 1.0
 * @date 2022/10/21 14:15
 */
public class Test {
    public static void main(String[] args) {
        Test test=new Test();
        test.testJacob();
        test.add(1,2);
    }

    /**
     * 测试jacob组件
     * 只作为测试jacob好用不好用
     * 如果遇到报错则 检查jacob-1.18-x64.dll有没有放到C:\Windows\System32文件夹下
     */
    public void testJacob() {
        ActiveXComponent xl = new ActiveXComponent("Excel.Application");
        Dispatch xlo = xl.getObject();
        try {
            System.out.println("jacob's version="+xl.getProperty("Version"));
            System.out.println("jacob's version="+Dispatch.get(xlo, "Version"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            xl.invoke("Quit", new Variant[] {});
        }
    }

    /**
     * 测试dll
     */
    public void add(int a,int b) {
        try {
            // 启动jacob线程
            ComThread.InitSTA();
            // MyTest 是要调用方法的命名空间namespace
            // TestClass 要调用方法的类名class
            ActiveXComponent com = new ActiveXComponent("MyTest.TestClass");
            // Dispatch对象看成是对COM组件的对象
            Dispatch dispatch = com.getObject();
            //sum是MyTest.dll中的一个方法 后边是传入的参数
            Variant ret = Dispatch.call(dispatch, "sum",a,b);
            //打印结果
            System.out.println("Dll返回的结果为"+ret.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 结束jacob所有线程
            ComThread.Release();
        }
    }
}

 4.记录调用dll时的报错及解决办法

4.1com.jacob.com.ComFailException: Can't map name to dispid

dll中的方法不能用static修饰

4.2com.jacob.com.ComFailException: Can't co-create object

dll导出时候没有根据步骤1.3导出(我觉得大概率是dll属性中没勾选为COM互操作注册)

4.3com.jacob.com.ComFailException: Can't get object clsid from progid

dll导出时候没有根据步骤1.3导出(我觉得大概率是dll属性中没勾选为COM互操作注册)

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
SanNiuSignal是一个基于异步socket的完全免费DLL;它里面封装了Client,Server以及UDP;有了这个DLL;用户不用去关心心跳;粘包 ;组包;发送文件等繁琐的事情;大家只要简单的几步就能实现强大的通信系统;能帮助到大家是本人觉得最幸福的事情,也希望大家 在用的过程中找出DLL中不足的地方;好改正;此DLL的苹果版和java版正在努力开发中......交流QQ:365368248;此演示源码下载地址:http://pan.baidu.com/s/1eQw1npw 里面包括了SanNiuSignal.DLL 下面为大家介绍一下 如何使用SanNiuSignal. 1 ) :TCPServer服务器,通过静态方法TxStart.startServer注册成功服务器ITxServer;然后通过ITxServer设置好各种属性;最后启动 ITxServer.StartEngine();就可以了;具体可以到demo里去看;相对来说比较简单,下面来说一下需要注意的地方 一:ITxServer.BufferSize,就是接收数据缓冲区大小;默认为1kb,不要小于50字节,而且要和客户端设置成一样;否则会出现不可预知 的错误;这个缓冲区的大小,不会影响你每次发送数据的大小;大小只能提高你的发送速度 二:ITxServer.sendMessage 发送前先判断此IPEndPoint客户端是否在线;因为如果不在线等情况发生;此方法没有任何消息产生;如 果发送成功并且对方已经收到;会触发发送成功的事件; 三:用户可以通过ITxServer.FileLog记录服务器的运行信息; 2 ) :TCPClient客户端,通过静态方法TxStart.startClient(服务器地址或网址, 服务器端口号)注册成功客户端ITxClient;然后通过 ITxClient设置好各种属性;最后启动ITxClient.StartEngine();跟服务器启动差不多;具体可以到demo里去看;客户端要注意的一些地 方 一:如果非服务器强制关闭客户端的情况下,掉线的话,客户端默认是要重连的;他的原理是这样的,每10秒重连一次;重连 ITxClient.ReconnectMax次如果失败;会自动关闭客户端引擎;在重连的过程中;你可以改变客户端连接服务器的IP地址和端口号;但 如果当断开的时候不想重连;可以设置ITxClient.ReconnectMax=0; 二:登录篇,在引擎启动之前,用户可以设置ITxClient.OutTime来设置超时时间;默认为10秒,也就是说10秒之内肯定会有一个登录结果 ;登录成功或登录失败。有了登录结果会触发登录结果事件; 3 ) :Udp引擎,通过静态方法TxStart.startUdp()注册成功UDP--IUdpTx;然后通过IUdpTx设置好各种属性;最后启动 IUdpTx.StartEngine();如果在启动之前要绑定端口号,请在这里设置IUdpTx.Port;否则是随机使用本地端口;无论是UDP还是服务器和 客户端;它们的很多方法和属性以及事件都是相同的,因为他们都继承了通信系统的基接口ITxBase;下面是UDP引擎要注意的地方 一:UDP的优势在于速度快但不太可靠;所以有些属性不能设置的太过,如IUdpTx.BufferSize;默认为1KB,如果在广域网上发送信息, 缓冲区大小不要超过默认值;否则数据会丢失,如果一次性数据大于1KB;也没事,系统会自动分包发送;不太会丢包。 4 ) :文件发送系统,通过静态方法FileStart.StartFileSend(IFileSendMust)生成一个文件发送系统IFileSend;其中IFileSendMust是 必须实现的一个接口;具体参照demo;然后通过IFileSend设置好各种属性;发送还是要通过前面的三个引擎系统发送的;如 ITxClient.SendFile 这时会返回一个文件标签,是一个整数;IFileSend可以通过操作这个标签来操作这个正在发送的文件;接收文件 系统也一样;也是通过文件标签来操作;文件续传也是一样,也要通过前面的三个通信引擎系统进行续传;因为文件系统不能决定用户 通过哪个通信系统进行续传的;例如IUdpTx.ContinueFile进行续传;大家也可以试一下 掉线之后重新连接也可以续传; 5 ) :文件接收系统,通过静态方法FileStart.StartFileReceive(IFileReceiveMust)生成一个文件接收系统IFileReceive;其中 IFileReceiveMust是接收方必须实现的一个接口;具体参照demo;然后通过IFileReceive设置好各种属性;下面来讲讲文件系统要注意 的几个要点 一:每个文件都有一个文件标签,发送系统和接收系统是通过控制这个标签来控制这个文件的;如果是同一个文件传输,标签也一样的; 二:要注意属性BufferSize缓冲区大小,他是代表一次传送的字节数;如果这个文件缓冲区越大,传输速度越快;具体要设置成多少,大 家自己去调试;TCP传输的话一般可以设置成比较大,但UDP的话这个不要超过1KB;所以传输大文件尽量不要用UDP这种不可靠的东东; 三:当网络等各种原因中断文件的时候;会触发文件中断事件;文件自动处于暂停发送或接收状态;等待续传;续传的发送方,如果对方 同意续传;对方将不会触发续传开始的方法;别的大家可以通过demo里去发现; 总结: 其实这个DLL相对来讲是比较简单的;大家只要掌握这五个接口;1:ITxServer TCP服务器接口 2:ITxClient TCP客户端接口 3:IUdpTx UDP接口 4:IFileSend 文件发送方接口 5:IFileReceive 文件接收方接口 前面三个接口是通过TxStart启动;后面二个文件接口 是通过FileStart启动 今天先讲到这里;希望这个DLL对大家有所帮助;不足之处希望通过QQ或博客园大家一起交流;谢谢 此演示源码下载地址:http://pan.baidu.com/s/1eQw1npw 里面包括了SanNiuSignal.DLL
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代码并实现更高效的程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

New 对象()

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值