2006年09月09日 星期六 04:46 P.M.
有时候真很难只使用java的东西的。word就是一个好例子,应为他太深入人心了。
要使用word,就必须使用word提供的api,在java里面方便的是通过一些jni封装好的东西调用com来操作。另外apache里面也提供了对word的一些简单读写。在poi项目里面。相对弱些。弱有弱的特点,简单读写比较方便。 尝试了jcom和jacob两个开源的项目。 jacob官方网址: http://danadler.com/jacob/ jcom 官方网址: http://sourceforge.net/projects/jcom jcom是日本人开发的项目,头一次接触java到com桥的东西,感觉他还是挺就手的。但是碰到问题后确实挺难办,怎么说我们都学英语这么多年了,看点英文文档英文注释还了解个大概,碰到日文就无能为力了,毕竟日语才学了那么一会。而jacob是英文的,还好,现在还没碰到什么问题,应为它的src包里面的例子挺全面的。jacob的功能比jcom强大多了,虽然没发现有文档,但是有例子就够了。 使用这方面的东西,都得做两件事,第一就是加入jar包,第二就是引入dll文件。加jar包就不说了,引入dll文件我的做法是:如果是工程就直接把那个dll扔到windos/system32/里面就行了,如果是单个执行程序,给vm arguments添加上 -Djava.library.path=f:/jcom就行了.ok. copy 个例子来试试吧。 jcom的示例代码(打开一个word文件,给它加入密码) ReleaseManager rm = new ReleaseManager(); IDispatch app = new IDispatch(rm, "Word.Application"); app.put("Visible", new Boolean(true)); IDispatch documents = (IDispatch) app.get("Documents"); IDispatch doc = (IDispatch) documents.method("open", new Object[] { "D://test.doc" }); //有哪些属性能改变,自己去查就行了。 //网址 http://msdn2.microsoft.com/zh-CN/library/microsoft.office.interop.word.aspx
doc.put("Password","123456");
遇到一个问题,当我想加入文档保护属性的时候,第二个参数无论怎么给都不对。 Object[] args = new Object[3]; args[0] = 0; args[1] = new Boolean(true); args[2] = new String("1234"); doc.method("Protect", args); 就这里老报错,郁闷。终于导致我使用另外一个桥接包。 jacob的示例代码(同样打开一个word文件,设密码就差不多操作了) ActiveXComponent objWord = new ActiveXComponent("Word.Application"); Dispatch wordObject = objWord.getObject(); Dispatch.put((Dispatch) wordObject, "Visible", new Variant(true)); Dispatch documents = objWord.getProperty("Documents").toDispatch(); Dispatch document = Dispatch.call(documents, "Open", "D://b.doc") .toDispatch(); 后来想监控通过jacob打开的word程序的事件,看了以下example。仿写了一段。 原理是需要同时启动一个线程监控着的。 public class WordThread extends Thread { public boolean quitHandled = false; public void run() { // this used to be 5 seconds but sourceforge is slow int delay = 5000; // msec // paired with statement below that blows up ComThread.InitMTA(); ActiveXComponent rm = new ActiveXComponent("Word.Application"); Dispatch wordObject = rm.getObject(); Dispatch.put((Dispatch) wordObject, "Visible", new Variant(true)); Dispatch documents = rm.getProperty("Documents").toDispatch(); Dispatch document = Dispatch.call(documents, "Open", "D://b.doc") .toDispatch(); WordEvents ieE = new WordEvents(); //这里为什么要写Word.Application.1我也不太清除,反正监控ie也是***.1的。 new DispatchEvents((Dispatch) rm, ieE, "Word.Application.1"); while (!quitHandled) { try { Thread.sleep(delay / 5); } catch (InterruptedException e) { } } ComThread.Release(); }
public class WordEvents extends InvocationProxy {
/** * override the invoke method to loga ll the events */ public Variant invoke(String methodName, Variant targetParameter[]) { System.out.println("Received event from Windows program" + methodName); //当监控到关闭的时候就把监控线程终止。 if (methodName.equals("Quit")) { quitHandled = true; } return null; } } } 之后就是启动这个线程就行了。 public void threadWord() { // this line starts the pump but it runs fine without it ComThread.startMainSTA(); // remove this line and it dies // /ComThread.InitMTA(true); WordThread aThread = new WordThread(); aThread.start(); while (aThread.isAlive()) { try { Thread.sleep(1000); } catch (InterruptedException e) { // doen with the sleep // e.printStackTrace(); } } System.out.println("Thread quit, about to quit main sta"); // this line only does someting if startMainSTA() was called ComThread.quitMainSTA(); System.out.println("did quit main sta"); } |