Zh/Uno/FAQ
关于Uno, UDK, URE等相关的常见问题。基于在dev@udk.openoffice.org邮件列表中提出的问题与回答。如果您有任何评论或问题,在那里提出同样可以得到答复。
Contents
- 1 普遍问题
- 2 开发相关问题
- 2.1 能给我些代码示例吗?
- 2.2 如何生成C++数据类型定义?
- 2.3 regcomp是干什么用的?
- 2.4 哪里能找到OpenOffice.org API?
- 2.5 如何测试我自己的组件?
- 2.6 一共存在几种桥接?
- 2.7 什么时候要用到桥接?
- 2.8 怎样给数据结构设置缺省值?
- 2.9 嘿,我的组件崩溃了,是怎么回事?
- 2.10 为什么说编写编译器相关的C++桥接令人头痛?
- 2.11 如何为一个RISC CPU实现C++桥接?
- 2.12 载入一个文档时该使用哪个属性值(PropertyValue)?
- 2.13 如何打开一个文档并将它保存为HTML格式?
- 2.14 如何把OpenOffice.org文档保存为XML格式?
- 2.15 是不是每次都要用queryInterface?
- 2.16 cannot dump'com/star/uno/RuntimeException'是什么意思?
- 3 文档相关问题
普遍问题
嘿,OpenOffice.org的组件技术真棒。我怎样才能参与进来?
好极了,我们永远欢迎您。关于帮助的切入点请参阅 开放任务列表。如果您对于其中的任何任务有任何疑问请不要犹豫提出来。把它发到dev@udk.openoffice.org.
UNO依赖于OpenOffice.org吗?
不久的将来,在OpenOffice.org的安装包之外将会有一个办公软件开发工具包(Office Development Kit)可供下载,这个开发工具包包含编译组件所需要的所有文件(头文件,库,工具软件,等等)。开发工具包也将包含示例。这些示例的makefile只需要有gnumake就可以编译(而不需要整个OpenOffice.org编译环境)。可以用这些makefile作为模板来把您的UNO组件集成到您的编译环境里。
UNO是不是和微软的COM技术类似?
是的,UNO可以看作完全独立于办公软件本身的组件模型。它与COM是直接的竞争关系,您可以在这里找到它所具有特性的列表。
什么是ODK?
办公软件开发工具包(ODK)在UDK的基础上增加了文档,API(更多IDL文件),以及示例。UDK是ODK的一个子集。如果您想要扩展OpenOffice.org的功能,或用OpenOffice.org制作解决方案,ODK将适合您的需要。UDK是一个独立的对象模型,可以脱离OpenOffice.org单独使用。在向Gnome以及XPCOM中集成,以达到统一开源对象模型(Open Source Object Model)的长期目标的过程中,UDK将是主要的讨论对象。未来,应该可以编写依赖于ODK的组件和独立于OpenOffice.org的组件。 办公软件开发工具包使软件工程师可以不需要笨重的OpenOffice.org编译环境就可以为OpenOffice.org开发组件。因此,ODK包含基本(以及重要的)库的二进制文件,C++头文件,所有的idl文件,.jar文件以及开发工具(代码生成器,组件注册工具,等等)。ODK还将包含一些源码与makefile,只要有gnumake和一个C++编译器就可以编译,您可以用这些makefile作为例子集成到您的编译环境里。未来,随每个版本的OpenOffice.org都会提供开发工具包并可以独立下载。
你们为什么不用Java或CORBA做中间件?
我们需要的中间件可以用于细粒度组件,至少是进程内组件。在同一种语言中使用不同的UNO组件是不应当有开销的(例如,在C++中只是调用一个虚函数)。不幸的是,目前CORBA没有进程内组件的接口与数据结构的设计。唯一的通信方法是通过IIOP协议。对于进程内通信,这种开销实在太大。我们想要语言无关,让UNO作为像Java,C++,C和其它不同语言间的中介,这并不是CORBA的目标。UNO的另一个目标是成为像COM/DCOM,CORBA,Java和XPCOM这些不同对象模型间的中介,这也不是其它对象模型所具有的目标。
UNO和CORBA间有什么不同点?
UNO不生成桩代码(stub code)。在过去的UNO2实现中我们是生成的。那时的一个问题是,生成的桩代码非常大(尽管当时的API数据类型比现在还要少,大概也有12MB!)在UNO3(现在的版本)中,我们决定泛型地调用具体实现部分。给C++生成的,除去纯虚类只有用来返回数据类型的getCppuType()函数。完整的数据类型描述是在运行时从一个二进制仓库中读取的。在数据类型数量增加的情况下,这种方法具有空间开销小的优点。如果想了解UNO和CORBA间的更多不同点,请参考以下对比。
UNO IDL和CORBA IDL间有什么不同点?
UNO IDL具有:
- 数据结构(structure)与异常(exception)的继承关系
- 一种新的服务(service)类型
- 可以给枚举(enumeration)值赋具体的值
- 没有数组(array)类型(但为此引入了序列(sequence))
- 没有共用体(union)类型
我能把OpenOffice.org组件当作Java Beans使用吗?
可以,OpenOffice.org bean(OOoBean)项目使OpenOffice.org组件可以用于Java应用程序。请访问OOoBean以获得相关信息、源码、以及二进制档的下载。 OOo Bean具有一下特点:
- 将OpenOffice.org组件嵌入Java应用程序(application)或(applet)中。
- 可以通过Java访问全部StarOffice API,来编写您自己的应用程序。
这个项目刚刚开始,因此请留意可能存在的bug、不完整的文档以及安装问题等等。我们欢迎每位对OpenOffice.org和Java感兴趣的人士参与到项目中来,或是在他们的应用程序中使用OOoBean。
开发相关问题
能给我些代码示例吗?
C++示例
位置 | 内容 |
udk/remotebridges/examples/officeclient.cxx | 这个示例说明了如何建立到OpenOffice.org文档的进程间桥接(bridge)。
无论您的组件是用于Windows还是Linux,编写上都不存在区别。 |
udk/product/examples/ | 更多示例。 |
HTML 文档
位置 | 内容 |
http://udk.openoffice.org/cpp/man/tutorial/remotedemo.html | 远程通信demo教程。 |
http://udk.openoffice.org/cpp/man/component_tutorial.html | 在UNO空间中编写的组件。 |
http://udk.openoffice.org/cpp/man/tutorial/unointro.html | C++ UNO指南。 |
http://udk.openoffice.org/common/man/concept/unointro.html | 编程语言无关的UNo指南。 |
Java示例
我们缺少一篇优秀的关于如何在Java下开始开发的文档。您可以直接查看源码。在jurt项目中也有一些示例,您可以使用以下命令下载:
$ cvs -d :pserver:anoncvs@anoncvs.services.openoffice.org:/cvs co udk/jurt
您可以在demo目录下的源码中找到一些示例。
位置 | 内容 |
jurt/demo/com/sun/star/demo/TestOffice.java | 启动一个进程间桥接并在office中新建几个文档。 |
jurt/demo/com/sun/star/comp/demo/ | 这里可以找到一些关于如何创建一个Java组件的样例代码。这个样例可以注册到一个office中并在这个office中运行。 |
我们还建议参考sun开发者网络(http://developers.sun.com/),您可以点击Download SDK下载到StarOffice程序员教程。它包含了一些关于某些API问题的示例。关于office API更深入的问题的问题请通过dev@api.openoffice.org询问。
如何生成C++数据类型定义?
- 新建用来描述接口的.idl文件
- 使用unoidl生成.urd文件
- 使用regmerge将新数据类型合并到系统注册表中
- 使用cppumaker生成C++数据类型(在Java中使用javamaker)
- 在Java中,编译生成的接口,将它们添加到您的CLASSPATH中
regcomp是干什么用的?
unoild将IDL描述转换成一个二进制库的格式,每个IDL数据类型在运行时都需要这个数据类型信息。unoidl生成的输出文件只包含定义的数据类型的信息。它不包含所有数据类型的全部数据类型描述。因此,需要使用regmerge将新数据类型安装到类型库applicat.rdb中。如果某人开发一个UNO组件,他必须支持或输出一些管理用的函数(例如,component_writeInfo)。关于支持哪些服务以及实现的名称,开发者要在component_writeInfo函数里给出相关信息。之后服务管理器(service manager)将使用这些信息来生成组件的实例。因此,如果您开发您自己的组件,您必须将您的组件安装到运行时中去。用regcomp就可以做到这点。regcomp读取component_writeinfo函数,并利用这些信息进行一些管理工作。例如,这个组件支持的所有服务都将插入一个全局的SERVICES段中,这个段要被服务管理器用到。在这个段中建立了服务名与实现名的相互联系。在IMPLEMENTATIONS保留区中,您可以为您的组件找到一个正确的段,它的值等于在component_writeInfo函数中定义的键值。请查看一下您安装在office目录下的applicat.rdb。
$ regview applicat.rdb /SERVICES $ regview applicat.rdb /SERVICES/<service_name> $ regview applicat.rdb /IMPLEMENTATIONS $ regview applicat.rdb /IMPLEMENTATIONS/<implementation_name>
因此,安装一个新组件的时候需要使用regcomp。在类型库中安装新数据类型的时候需要使用regmerge。
哪里能找到OpenOffice.org API?
请访问API项目网站。
如何测试我自己的组件?
如果您开发了一个新组件,最后会生成一个共享的动态链接库(DLL)。当接到请求使用您实现的服务时,将会载入这个DLL。为了让您的组件在OpenOffice.org中能够看到和使用到,需要把您的服务注册成一个外部组件。您需要按照下面步骤来做到这一点:
- 将您的DLL拷贝到.../program目录下。
- 将regcomp工具拷贝到.../program目录下。您可以在UDK的cpputools模块中找到这个工具。
- 使用regcomp工具:
$ regcomp -register -r applicat.rdb -c foo.dll
- 如果您开发了自己的接口或数据类型,您需要将这些新数据类型注册到UNO类型库中。您需要UDK的registry模块中的regmerge工具来做到这点。unoidl工具会生成一个foo.urd文件,它包含了新数据类型。可以在您的组件的输出目录下找到这个文件。
- 使用regmerge工具:
$ regmerge applicat.rdb /UCR foo.urd
IDL数据类型中的所有数据类型定义都存放在保留键值UCR下面(UNO core reflection,UNO核心映射) - 组件与新数据类型注册后您就可以通过服务管理器为您的服务生成实例了。
使用basic,有一种既快又便捷的方法可以给一个新服务生成实例。新建一个basic脚本输入下面的代码:
Sub Main s = createUnoService("YourSerivceName") msgbox(s.dbg_supportedinterfaces) End Sub
如果实例化过程成功,对话框将显示对象支持的全部接口。 可以在这个目录下的README文件中找到更多信息http://www.openoffice.org/source/browse/udk/product/examples/
一共存在几种桥接?
目前存在4种桥接:C++桥接、Java桥接、UNO远程协议(URP)桥接以及IIOP桥接。
什么时候要用到桥接?
如果您是在C++里开发组件,记得由同一个编译器编译的组件,在进程内相互调用,是不需要在接口间桥接的。组件加载器可以识别这一点并直接使用实现好的C++接口。但如果您使用脚本语言(例如basic)调用一个Java组件,或是使用远程UNO调用其它进程,就要用到桥接了。
怎样给数据结构设置缺省值?
给数据结构设置缺省值是不可以的,因为这些缺省值不能用在其它对象模型(例如CORBA)里。也不可以通过修改unoidl为数据结构生成的缺省构造函数给变量成员设置缺省值。生成的缺省内联构造函数可以在.hpp文件中找到。构造函数只能把给定的初始值赋给变量成员。
嘿,我的组件崩溃了,是怎么回事?
由于只从堆栈很难知道错误出在哪里,请尽可能地附上更多的信息。如果您幸运地恰好是这个服务的作者,您可以附上组件的实现代码以及生成对象实例的代码。如果组件不是您开发的,那您将不得不联系组件的开发者了。
为什么说编写编译器相关的C++桥接令人头痛?
UNO的目标是为UNO组件的开发者和使用者提供最简单的语言绑定、最少的生成代码与最快的运行速度。用现在的技术可以达到这个目标。例如,在C++中调用不存在额外开销,因为一个从C++到C++的调用只是调用一个虚函数。编译时不会生成代码,调用是在运行时由桥接完成的。UNO C++语言绑定比其它绑定(CORBA、COM)更小。从另一个角度来说,写一个C++桥接是一件困难的事,但对于每一个编译器、操作系统和处理器只需要做一次。要做到语言绑定的确存在更简单的方法,但它们并不是更好的方法。乍看来,一个从C++到UNO的桥接是非常依赖于编译器与应用程序二进制接口(ABI)的,似乎根本不具有可移植性。然而必须说明的是,对于大多数编译器来说桥接的代码是非常相似的。主要的差异在于生成的虚函数地址表(vtable),进行C++虚函数调用,已经异常处理。
如何为一个RISC CPU实现C++桥接?
在RISC机器上,函数的形参是在寄存器中传递的,然而,C++桥接代码要操作一个C++层与UNO层之间的栈。想要知道这个问题是如何解决的,请参阅sunpro5 solaris sparc的桥接。寄存器的内容被直接压栈(扩展了栈中的非寄存器参数[在多于6个的情况下])。
载入一个文档时该使用哪个属性值(PropertyValue)?
一个文档总是由加载器用一个空属性实参打开的
PropertyValue [] szEmptyArgs = new PropertyValue [0]; String doc = "private:factory/swriter"; aDoc = oCLoader.loadComponentFromURL(doc, "_blank", 0, szEmptyArgs );
用这些参数,可以强制让OpenOffice.org使用某个特定的过滤器(filter),只读方式打开文档,为密码保护的文档设置密码。给spreadsheet用的csv过滤器有一些附件的选项,这些选项与UI中的pick list相同,这些选项被存放在soffice.ini/sofficerc中。
如何打开一个文档并将它保存为HTML格式?
可以使用下面的代码样例:
PropertyValue [] mypv = new PropertyValue[1]; mypv[0] = new PropertyValue(); mypv[0].Name = new String("FilterName"); mypv[0].Value = new String("scalc: Text - txt"); mypv[0].Handle = -1; mypv[0].State = PropertyState.DEFAULT_VALUE; aStore.storeAsURL(doc, mypv); //aStore is a XStorable object, and doc is url string
如何把OpenOffice.org文档保存为XML格式?
可以使用下面的代码样例:
sub SaveXML dim mProps(0) as new com.sun.star.beans.PropertyValue mProps(0).Name = "FilterName" 'This works with 614 mProps(0).Value = "swriter: StarOffice XML (Writer)" oDesk = createUNOService("com.sun.star.frame.Desktop") 'For some reason, ActiveComponent no longer works: oComponent = oDesk.CurrentComponent() oComponent.storeAsUrl("file:///C|/Tmp/startemp.xml",_ mProps()) end sub
是不是每次都要用queryInterface?
不需要直接调用queryInterface。更方便的方法是使用一个特殊的Reference构造函数模板。不使用
::com::sun::star::uno::Any x = xI->queryInterface( ::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XTransliteration>*)0)); x >>= transRef;
而使用:
transRef = Reference< XTransliteration >( xI, UNO_QUERY );