`
sunxiuling
  • 浏览: 33650 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

java 如何调用com组件接口方法。

阅读更多

大家都知道com组件的接口方法是基于windows下开发的。要在java里调的话。就要用到JNI技术。JNI是Java Native Interface的缩写,JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。尤其是c++或是c写的com组件接口。

JNI(Java Native Interface)的书写步骤 一般分为以下:

1、      编写带有native声明的方法的java类
2、    使用javac命令编译所编写的java类
3、    使用javah ?jni java类名生成扩展名为h的头文件
4、    使用C/C++实现本地方法
5、    将C/C++编写的文件生成动态连接库

写个例子来说明,最常用的还是hello  world 的例子吧。

class HelloWorld {
public native void displayHelloWorld();

static {
System.loadLibrary("hello");
}

public static void main(String[] args) {
new HelloWorld().displayHelloWorld();
}
}

注意:LoadLibrary中的DLL文件名称可以随便定.只要做好的动态链接库改名成这个字符串就可以了

如果你想将一个方法声明为本地方法的话,必须将方法声明为native方法,并且不能实现。 做好该步准备以后,用javac TestNative.java生成.class.检验语法.  语法检查通过以后,用javah HelloWorld 生成.h的C头文件. 然后打开VC++6.0,新建->; 工程 ->; win32 Dynamic-Link Library .在向导中选择空工程. 把刚才javah生成的那个头文件加入工程 .然后 文件->;新建->;textFile 自己做一个.c文件.实现自己的native函数.例子如下:

1 #include
2 #include "HelloWorld.h"
3 #include

4 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
{
printf("Hello world!\n");
return;
}

备注:
其中的HelloWorld.h通常在 jdk\include\ 可以先拷贝到VC安装目录下的include目录下。一劳永逸,以后可以方便使用JNI技术,全编译一下工程,如果没有出错,则此时生成动态链接库成成功。把动态链接库拷贝到HelloWorld .java所在的目录上. 
 运行java HelloWorld 看结果吧.

 

在实际应用中比较麻烦是数据类型的转换。因为要解决java和C++数据类型互通的问题。比如java里的string 如何映射为c++里相应的字符。还希望大家一起讨论。


 

 

分享到:
评论
20 楼 liangwj72 2007-09-13  
大家总不可能自己写这些JAVA处理COM callback的接口吧.....

我所介绍的3个工具已经是很好用的了,其中JIntegra是个人认为最为成熟的方案。是我们这边最终使用的方案,在我们这边400并发/秒的系统中,运行得很稳定。其他两个在高并发的情况下,虚拟机立刻崩溃。

至于JNI,绝对来说,几乎是什么都可以实现,我们这边还用jni实现通过修改网卡驱动程序,通过更改TCP连接的三次握手方式实现半连接方式的端口扫描。可以说jni直接操作系统的底层都没有问题,但我评价一个技术方案的可行性更多的取决于开发量、可扩展性,使用价值。真的要用jni处理com回调,代价太大了,特别是在有现成工具的情况下。所以我才会说,用jni调用com组件不可行。


19 楼 rehte 2007-09-13  
pikachu 写道

不过初始化COM需要再native里作,并且要保留jni环境让回掉函数处理

这个当然。
18 楼 rehte 2007-09-13  
嗯,麻烦是麻烦了些,但并不是不能实现,思路和方法很多。我见过的就有很多种。
在c中调用对象的notify并不是什么难事,这都是JNI规范中写的明明白白的,我觉得还是内存管理是个麻烦事。AWT很好的解决这一点,而SWT将这个任务交给了开发者,让他们按照谁创建,谁释放的原理来解决。
总之,说java调用com困难,的确是这样。但用jni实现并不是不可能的,有很多方法和思路的。
17 楼 pikachu 2007-09-13  
rehte 写道
pikachu:
我只是说大致原理,我对M$的COM并不熟悉。按照你提供的信息那就更简单了,在类构造函数初始化时初始化这个COM对象,挂到COM的事件连接点上,在添加事件处理器时使用native方法注册对应的IDispatch接口,并将java处理器句柄传给它,在IDipstatch处理方法中回调java处理器相应的方法就可以了。


基本上正解
不过初始化COM需要再native里作,并且要保留jni环境让回掉函数处理.
难点不在于思路,而在于实现细节,内存管理,线程同步,以及不稳定的com环境(谁发明的com这套狗屁东西).
说实话,要我设计两边接口的话,稳妥点我会用xml作参数传递的.处理string总比处理一堆自定义对象稳妥.

好了好了,大家拉拉手,还是好朋友.
16 楼 liangwj72 2007-09-13  
嗯,刚才没看清你的想法,你的想法是我猜测这些中间件的实现原理中的一种。

这种方法的难点在与要用代码实现在C中间notify一个java那边传过来的锁。事件返回对象的内存管理也很麻烦,C无法释放这些内存,只能由java这边申请内存,然后java自己管理。
15 楼 rehte 2007-09-13  
pikachu:
我只是说大致原理,我对M$的COM并不熟悉。按照你提供的信息那就更简单了,在类构造函数初始化时初始化这个COM对象,挂到COM的事件连接点上,在添加事件处理器时使用native方法注册对应的IDispatch接口,并将java处理器句柄传给它,在IDipstatch处理方法中回调java处理器相应的方法就可以了。
14 楼 pikachu 2007-09-13  
rehte 写道
liangwj72:
我现在才明白你所谓的困难是什么,你意思是在c那边启动一个线程异步调用java代码困难?
其实根本不用那么麻烦,也没有你想像的那么麻烦。大体思想是在java中启动一个线程,线程循环调用一个native方法,该方法获取下一个com事件(或者任何其他Windows事件),该方法是阻塞式方法,当没有事件时就处于阻塞状态,当获得一个事件后,只需简单调用你定义的java interface的回调函数就行了。
jdk的源代码中到处是这种例子。SWT源代码也是这样。


COM 事件≠ windows事件.
要接收COM事件,你必须
1创建一个COM对象
2挂到COM的事件连接点上
3处理该死的IDispatch接口
4最后才是处理真正的事件

前面3步要是用VC模板辅助,估计生成个一两百行代码也就够了 

不过liangwj72的问题,用 Observer模式解决就是了
引用
可异步的事件通知呢?C的代码如何启动一段java的代码回调一个java实例的方法可是个麻烦问题。




1 设计一个EventDispatch类
2 作n个Static的XXXEventCallback方法对应你的com事件
3 想办法让你的那些个要处理事件的实例注册到这个EventDispatch里
4 jni里调用EventDispatch 的static方法
5 EventCallback再调用实例的方法


不掺和口水战,下班,回家!!
13 楼 rehte 2007-09-13  
线程循环调用native方法获取事件时,当然要用同步锁了,这个是生产者-消费者的典型用例,我只不过是没有进一步说明罢了,以为你明白。
12 楼 liangwj72 2007-09-13  
人家不是用“线程循环调用一个native方法”干的,是用同步锁....
11 楼 rehte 2007-09-13  
liangwj72:
我现在才明白你所谓的困难是什么,你意思是在c那边启动一个线程异步调用java代码困难?
其实根本不用那么麻烦,也没有你想像的那么麻烦。大体思想是在java中启动一个线程,线程循环调用一个native方法,该方法获取下一个com事件(或者任何其他Windows事件),该方法是阻塞式方法,当没有事件时就处于阻塞状态,当获得一个事件后,只需简单调用你定义的java interface的回调函数就行了。
jdk的源代码中到处是这种例子。SWT源代码也是这样。
10 楼 liangwj72 2007-09-13  
pikachu 写道

--! COM事件和SWT/AWT/Swing的事件系统原理类似,但在实现上差别太大了.

说实话,要白手起家把Java和com串起来,问题不在接口,而在于要用c写一堆莫名其妙的东西.


接口是个问题,关键在于事件是异步的,java调C容易,就是虚拟机把执行权交给一段C的代码而已,有比较简单的JNI接口。可异步的事件通知呢?C的代码如何启动一段java的代码回调一个java实例的方法可是个麻烦问题。

现在有这些中间件还好,几行代码可以搞定。如果没有,就只能自己写一个服务程序监听c那边发生的事件,然后通知java这边执行代码,或者用MessageQueue之类的异步机制,要写无数的代码才能搞定。

9 楼 pikachu 2007-09-13  
rehte 写道
JAVA调COM太麻烦了,这个我承认啊。但我反驳的是你的jni不能搞定事件通知的论调。你自己举的解决java com的解决方案已经反驳了自己,我举的证据SWT/AWT/Swing的事件系统也是证据。
我没有义务向你提供任何证明代码去,也没有必要去证明去。如果你想弄明白,自己去学习它们的代码去。


--! COM事件和SWT/AWT/Swing的事件系统原理类似,但在实现上差别太大了.

说实话,要白手起家把Java和com串起来,问题不在接口,而在于要用c写一堆莫名其妙的东西.
8 楼 pikachu 2007-09-13  
 这帖子也就说了java如何调用本地native代码,和com一点边都搭不上.连IUnknown都没有出现<br/>
<strong><br/>
</strong>
7 楼 rehte 2007-09-13  
JAVA调COM太麻烦了,这个我承认啊。但我反驳的是你的jni不能搞定事件通知的论调。你自己举的解决java com的解决方案已经反驳了自己,我举的证据SWT/AWT/Swing的事件系统也是证据。
我没有义务向你提供任何证明代码,也没有必要去证明。如果你想弄明白,自己去学习它们的代码。
6 楼 liangwj72 2007-09-13  
对,就是给个实现JNI事件通知的例子. 象楼主一样,象我一样,给出真实、运行过代码。别光说,但又拿不出证明。

顺便补充一下上面我的例子中其他语言调用COM的代码。以下代码可以看到C#调用COM的代码比java的简单多了,就算是不会的人也猜得出这个com其实就是通过add方法传入两个整数,然后在事件相应中吧两个两个整数的处理结果输出。属于异步调用过程,上面例子中的main和disp_result在分别在两个线程中执行。

结论还是:JAVA调COM太麻烦了

VC#2005测试代码
using System;
using System.Collections.Generic;
using System.Text;

using sample3Lib;

namespace CSClient
{
    class Program
    {
        static void evtProcess(int rst)
        {
            Console.WriteLine(rst);
        }

        static void Main(string[] args)
        {
            DispConnectClass disp = new DispConnectClass();
            disp.Result += new _IDispConnectEvents_ResultEventHandler(disp_Result);
            disp.Add(1, 2);            
        }

        static void disp_Result(int nVal)
        {
            Console.WriteLine(nVal);
        }
    }
}



顺便补充一下COM的IDL
import "oaidl.idl";
import "ocidl.idl";

[
	object,
	uuid(B2584167-40E5-413A-85D3-056CC6AA4057),
	helpstring("IDispConnect 接口"),
	pointer_default(unique)
]
interface IDispConnect : IUnknown{
	[, helpstring("方法Add")] HRESULT Add([in] LONG n1, [in] LONG n2);
};
[
	object,
	uuid(E38136E3-E271-46F2-B460-CF43A2A5BC1D),
	dual,
	nonextensible,
	helpstring("IEvent2 接口"),
	pointer_default(unique)
]
interface IEvent2 : IDispatch{
	[id(1), helpstring("方法Multiply")] HRESULT Multiply([in] LONG n1, [in] LONG n2);
};
[
	uuid(35CE13A7-14A1-4493-A16A-FEBD4843AED2),
	version(1.0),
	helpstring("sample3 1.0 类型库")
]
library sample3Lib
{
	importlib("stdole2.tlb");
	[
		uuid(32A65970-38E7-47A8-A923-3C61F60D362C),
		helpstring("_IDispConnectEvents 接口")
	]
	dispinterface _IDispConnectEvents
	{
		properties:
		methods:
			[id(1), helpstring("方法Result")] HRESULT Result([in] LONG nVal);
	};
	[
		uuid(85BC3789-164A-4BF0-A206-7833A832F6A8),
		helpstring("DispConnect Class")
	]
	coclass DispConnect
	{
		[default] interface IDispConnect;
		[default, source] dispinterface _IDispConnectEvents;
	};
	[
		uuid(D58AF39C-DA5C-47E1-AB40-C86FC61A2F19),
		helpstring("_IEvent2Events 接口")
	]
	dispinterface _IEvent2Events
	{
		properties:
		methods:
			[id(1), helpstring("方法Result")] HRESULT Result([in] LONG nVal);
	};
	[
		uuid(1DF179A6-4560-4364-8102-01F8713534C8),
		helpstring("Event2 Class")
	]
	coclass Event2
	{
		[default] interface IEvent2;
		[default, source] dispinterface _IEvent2Events;
	};
};
5 楼 rehte 2007-09-13  
给个什么例子?
给个实现JNI事件通知的例子?
SWT的实现以及你列的都是使用JNI实现的
还有AWT/Swing的事件循环系统也是这样的
4 楼 liangwj72 2007-09-13  
rehte 写道
谁说jni搞不定事件通知了?搞不定你列得这几个方案怎么实现的?SWT怎么实现的?只是你不会用罢了。


好,请给个例子
3 楼 rehte 2007-09-13  
谁说jni搞不定事件通知了?搞不定你列得这几个方案怎么实现的?SWT怎么实现的?只是你不会用罢了。
2 楼 liangwj72 2007-09-13  
如果要用java调com,不要用jni,因为jni搞不定com的事件通知

选择一:商业用途建议用J-Integra for COM。
优点:稳定,使用简单
缺点:只有商业版,收费的,贵死。
取巧的办法:weblogic中带了这套工具,听说weblogic很多盗版的....

例如以一个com中有add(int,int)的方法,并有一个事件通知。样例代码如下:
public class ConnectPointComTest {
    static {
        System.setProperty("JINTEGRA_NATIVE_MODE", "");
        System.setProperty("JINTEGRA_COINIT_VALUE", "2");
    }

    public void run() {
        try {
            _IDispConnectEventsAdapter evt=new _IDispConnectEventsAdapter();
            final DispConnect dcon = new DispConnect();
            dcon.add_IDispConnectEventsListener(evt);
            dcon.add(14, 5);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

dispConn开头的类用J-Integra for COM提供的工具生成的。
使用起来就象使用普通的java类一样的简单。

选择二: JACOB - Java COM Bridge
优点:开源,免费的,效果高
缺点:超过10个并发就死翘翘了,代码不好看。

同样是上面的那个com,样例代码:
public void run() {
    Dispatch test = new Dispatch("MyCOM.Test");
    MyCOMEvent myCOMEvent = new MyCOMEvent();
    DispatchEvents de = new DispatchEvents(test, myCOMEvent);
     Dispatch.call(test, "Add",90,68);
    Variant ret = Dispatch.call(test, "Sum", 3, 6);

    de.safeRelease();
    test.safeRelease();
}

可以看到jacob的调用方式,类似与我们通过反射方式获得实例的方法,然后在调用方法的过程。麻烦啊

选择三:Jacozoom
优点:使用方法和J-Integra for COM类似,一样的简单
缺点:和jacob一样的不稳定,仅仅是稍微好点,并发超过20个才崩溃,收费的。
样例代码懒得写了。

评价
没事就不要用java调com,再简单的代码也简单不错用c#调com,而且效率很有问题,调用10万次后计算出平均每次调用时间为1.7毫秒,这个效率实在太低了。
1 楼 alexsunny 2007-09-11  
听说过javacom

相关推荐

    java调用com组件实例

    接口中的方法声明需要使用`@DeclDLL`注解,指定对应的COM方法。 3. **加载COM组件**:使用`ActiveXComponent`类加载COM组件。例如: ```java ActiveXComponent excel = new ActiveXComponent("Excel.Application")...

    jcom java调用com+组件

    Java调用COM+组件是一种常见的跨语言交互技术,它允许Java应用程序利用已有的COM(Component Object Model)或COM+组件,这些组件通常是用其他语言如C++或Visual Basic编写的。这种技术对于整合遗留系统或者利用...

    JAVA + JACOB调用c++COM组件

    4. **调用COM方法**:通过`ActiveXComponent`对象,你可以调用COM组件的任何方法。对于接受`VARIANT*`和`BSTR*`参数的方法,可以使用`Variant`类来封装数据。`Variant`类支持多种数据类型,包括字符串、整型、浮点型...

    java调用WPS或pdfcreator的com接口实现doc转pdf

    本篇将详细讲解如何利用Java调用WPS(金山办公软件)或PDFCreator的COM接口来实现doc到pdf的转换。我们将探讨以下知识点: 1. **什么是COM接口**: COM(Component Object Model)是微软提出的一种组件对象模型,...

    java通过url调用接口

    在Java编程中,通过URL调用接口是一种常见的网络通信方式,尤其在Web服务和API交互中扮演着重要角色。这个项目提供了一种方法,通过URL发送请求并接收响应,然后将响应的字符串转换为JSON格式进行处理。接下来,我们...

    java操作com组件

    它的主要功能是将Java方法映射到COM方法,反之亦然,使得Java能够调用COM组件的方法和属性,就像它们是原生的Java类一样。 要使用JACOB,首先需要在Java项目中引入JACOB的jar文件。然后,你需要创建一个`...

    java调用天气的接口

    Java 调用天气接口的知识点总结 Java 调用天气接口是指使用 Java 语言来调用天气预报服务的 WebService,获取当前天气信息和天气预报数据。下面是相关知识点的总结: 1. Java 调用 WebService Java 调用 ...

    java调用AutoCAD接口绘图工具类

    利用Jacob调用AutoCAD接口绘图,实现绘制图形,不是调用Windows绘制图形界面,是真正的调用AutoCAD绘图,只是给了测试代码,具体功能自己摸索

    自己的Java远程方法调用组件

    Java远程方法调用(Remote Method Invocation,简称RMI)组件是一种关键的技术,它允许Java应用程序在不同的网络节点之间透明地调用对象的方法,仿佛这些对象都在本地进程中一样。这种技术在构建分布式系统、大型...

    java调用大漠插件的开源项目,使用njawin插件调用com组件,目前还在研究java 如何免注册调用com组件.zip

    "java调用大漠插件的开源项目" 提到了如何利用Java来调用这类插件,而“njawin插件”则是一个关键工具,它提供了一个桥梁,使得Java代码能够与COM组件进行通信。 NJAWIN是Java调用Windows API和COM组件的开源库。这...

    Java调用C#com方法

    【Java调用C# COM方法】是指在Java应用程序中调用由C#编写的COM组件。由于Java本身不直接支持对.NET Framework中的COM组件进行调用,因此需要借助中间层来实现这一目标。通常有两种常见的方式:一是使用JNA(Java ...

    java调用word组件

    java2word 是一个在java程序中调用 MS Office Word 文档的组件(类库)。该组件提供了一组简单的接口,以便java程序调用他的服务操作Word 文档。

    Java RPC调用示例

    1. **定义服务接口**:RPC调用始于定义一个服务接口,该接口声明了可供远程调用的方法。这些接口是客户端和服务端共享的契约,确保双方有相同的调用约定。 2. **序列化与反序列化**:由于数据需要在网络间传输,...

    java调用C#封装的dll方法

    ### Java调用C#封装的DLL方法 #### 第一种方法:Java利用JNA进行调用 **背景介绍:** 为了实现Java与C#之间的交互,一种常用的方式是通过调用C#封装的DLL文件来完成特定功能。这种方法涉及到.NET Framework与Java...

    C#调用java程序的方法

    C#调用Java程序的方法 C#调用Java程序的方法是指将Java类转化成dotnet类,在C#项目直接调用。这种方法可以使得C#项目可以调用Java类的方法,从而实现C#和Java之间的交互。 在这个过程中,我们需要使用IKVM(ynamic...

    使用JACOB工具调用COM组件

    JACOB利用Java本地接口(JNI)技术实现了这一功能,从而为开发者提供了对遗留COM组件的访问能力,这对于系统集成特别有用。 要使用JACOB,首先你需要下载并安装它。JACOB的最新版本可在其官方网站上获取,例如在...

    Java调AutoCAD接口.zip

    Java调用AutoCAD接口是一项技术性很强的工作,它允许开发者使用Java编程语言来控制和操作AutoCAD应用程序,实现自动化绘图、数据交换等任务。在本压缩包中,"Java调AutoCAD接口.zip"提供了使用Jacob库进行这项工作的...

    C语言调用java语言方法

    JNI是Java平台提供的一种接口,它允许Java代码调用本地(native)代码,也就是非Java语言编写的代码,反之亦然。在Android开发中,JNI常用于实现高性能计算、硬件访问或利用C/C++库。 要实现C语言调用Java语言的...

    java调用ocx控件,jacob,jar和dll文件

    Java调用OCX控件是跨平台编程中的一项技术挑战,因为OCX(Object Linking and Embedding Control)是微软Windows环境下的组件对象模型(COM)控件。然而,通过第三方库如Jacob(Java和COM的桥梁),Java开发者能够在...

    java调用window操作系统文本转语音并生成播放文件

    总之,Java调用Windows操作系统实现文本转语音并生成播放文件,涉及到JNI、COM组件、DLL编程、音频处理等多个方面,需要对Java和Windows API有深入理解。通过适当的技术选择和优化,可以创建出高效、灵活的文本转...

Global site tag (gtag.js) - Google Analytics