Java实现CORBA静态绑定(四)

本文主要内容涉及:

  • CORBA基本架构
  • IDL文件编写
  • POA示例实现
  • POA+TIE示例实现
  • ImplBase示例实现
  • ImplBase+TIE示例实现
  • Persistent示例实现

与POA方式相比,POA-Tie将继承方式,调整为委托方式,降低了软件的耦合度。

JDK提供了工具,可以直接生成stubs及skeletons接口代码:

idlj -fall Hi.idl
idlj -fallTie Hi.idl

编写server端代码:

import HiCorba.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;
import org.omg.PortableServer.POA;
import java.util.Properties;

class HiImpl extends HiPOA {
	private ORB orb;
	public void setORB(ORB orb_val) {
		orb = orb_val;
	}
	// implement sayHiTo() method
	public String sayHiTo(String someone) {
		return "\nHi, "+someone+" !"+"\n";
	}
	// implement add() method
	public int add(int numa, int numb) {
		return numa+numb;
	}
	// implement shutdown() method
	public void shutdown() {
		orb.shutdown(false);
	}
}

public class HiServer{
	public static void main(String args[]){
		try{
			// create and initialize the ORB
			ORB orb = ORB.init(args, null);
			// Get reference to rootpoa & activate the POAManager
			POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
			rootpoa.the_POAManager().activate();
			// create servant and register it with the ORB
			HiImpl hiImpl = new HiImpl();
			hiImpl.setORB(orb);
			// create a tie, with servant being the delegate.
			HiPOATie tie = new HiPOATie(hiImpl, rootpoa);
			// obtain the objectRef for the tie
			// this step also implicitly activates the object
			Hi href = tie._this(orb);
			// get the root naming context
			org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
			// Use NamingContextExt which is part of the Interoperable
			// Naming Service specification.
			NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
			// bind the Object Reference in Naming
			String name = "Hi";
			NameComponent path[] = ncRef.to_name( name );
			ncRef.rebind(path, href);
			System.out.println("HiServer ready and waiting ...");
			// wait for invocations from clients
			orb.run();
		}
		catch (Exception e){
			System.err.println("ERROR: " + e);
			e.printStackTrace(System.out);
		}
		System.out.println("HiServer Exiting ...");
	}
}

编写client端代码:

import HiCorba.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

public class HiClient{
	public static void main(String args[]){
		try{
			// create and initialize the ORB
			ORB orb = ORB.init(args, null);
			// get the root naming context
			org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
			// Use NamingContextExt instead of NamingContext. This is
			// part of the Interoperable naming Service.
			NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
			// resolve the Object Reference in Naming
			String name = "Hi";
			Hi hiImpl = HiHelper.narrow(ncRef.resolve_str(name));
			System.out.println("Obtained a handle on server object: " + hiImpl);
			System.out.println(hiImpl.sayHiTo("neohope"));
			System.out.println(hiImpl.add(70, 80));
			hiImpl.shutdown();
		}
		catch (Exception e) {
			System.out.println("ERROR : " + e) ;
			e.printStackTrace(System.out);
		}
	}
}

编译代码:

javac *.java HiCorba/*.java

测试,在三个shell或cmd窗口中依次运行:

#shell01
orbd -ORBInitialPort 1900
#shell02
java HiServer -ORBInitialPort 1900
>>HiServer ready and waiting ...
>>HiServer Exiting ...
#shell03
java HiClient -ORBInitialPort 1900 -ORBInitialHost localhost
>>Obtained a handle on server object: IOR:000000000000001349444c3a4869436f7262612f
  48693a312e300000000000010000000000000086000102000000000d3139322e3136382e35362e31
  0000744700000031afabcb00000000207673791300000001000000000000000100000008526f6f74
  504f4100000000080000000100000000140000000000000200000001000000200000000000010001
  00000002050100010001002000010109000000010001010000000026000000020002
>>Hi, neohope !
>>150

Java实现CORBA静态绑定(三)

本文主要内容涉及:

  • CORBA基本架构
  • IDL文件编写
  • POA示例实现
  • POA+TIE示例实现
  • ImplBase示例实现
  • ImplBase+TIE示例实现
  • Persistent示例实现

POA(Portable Object Adapter)提供了一组服务器端的接口以及操作,包括:跟踪侍服对象的实例化以及内存空间信息、服务对象的激活以及反激活、对象引用的创建、对象生命周期的管理等。

JDK提供了工具,可以直接生成stubs及skeletons接口代码:

idlj -fall Hi.idl

编写server端代码:

import HiCorba.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;
import org.omg.PortableServer.POA;
import java.util.Properties;

class HiImpl extends HiPOA {
	private ORB orb;
	public void setORB(ORB orb_val) {
		orb = orb_val;
	}
	// implement sayHiTo() method
	public String sayHiTo(String someone) {
		return "\nHi, "+someone+" !"+"\n";
	}
	// implement add() method
	public int add(int numa, int numb) {
		return numa+numb;
	}
	// implement shutdown() method
	public void shutdown() {
		orb.shutdown(false);
	}
}

public class HiServer {
	public static void main(String args[]) {
		try{
			// create and initialize the ORB
			ORB orb = ORB.init(args, null);
			// get reference to rootpoa & activate the POAManager
			POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
			rootpoa.the_POAManager().activate();
			// create servant and register it with the ORB
			HiImpl hiImpl = new HiImpl();
			hiImpl.setORB(orb);
			// get object reference from the servant
			org.omg.CORBA.Object ref = rootpoa.servant_to_reference(hiImpl);
			Hi href = HiHelper.narrow(ref);
			// get the root naming context
			// NameService invokes the name service
			org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
			// Use NamingContextExt which is part of the Interoperable
			// Naming Service (INS) specification.
			NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
			// bind the Object Reference in Naming
			String name = "Hi";
			NameComponent path[] = ncRef.to_name( name );
			ncRef.rebind(path, href);
			System.out.println("HiServer ready and waiting ...");
			// wait for invocations from clients
			orb.run();
		}
		catch (Exception e) {
			System.err.println("ERROR: " + e);
			e.printStackTrace(System.out);
		}
		System.out.println("HiServer Exiting ...");
	}
}

编写client端代码:

import HiCorba.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

public class HiClient
{
	static Hi hiImpl;
	public static void main(String args[])
	{
		try{
			// create and initialize the ORB
			ORB orb = ORB.init(args, null);
			// get the root naming context
			org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
			// Use NamingContextExt instead of NamingContext. This is
			// part of the Interoperable naming Service.
			NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
			// resolve the Object Reference in Naming
			String name = "Hi";
			hiImpl = HiHelper.narrow(ncRef.resolve_str(name));
			System.out.println("Obtained a handle on server object: " + hiImpl);
			System.out.println(hiImpl.sayHiTo("neohope"));
			System.out.println(hiImpl.add(70, 80));
			hiImpl.shutdown();
		} catch (Exception e) {
			System.out.println("ERROR : " + e) ;
			e.printStackTrace(System.out);
		}
	}
}

编译代码:

javac *.java HiCorba/*.java

测试,在三个shell或cmd窗口中依次运行:

#shell01
orbd -ORBInitialPort 1900
#shell02
java HiServer -ORBInitialPort 1900
>>HiServer ready and waiting ...
>>HiServer Exiting ...
#shell03
java HiClient -ORBInitialPort 1900 -ORBInitialHost localhost
>>Obtained a handle on server object: IOR:000000000000001349444c3a4869436f7262612f
  48693a312e300000000000010000000000000086000102000000000d3139322e3136382e35362e31
  0000732000000031afabcb000000002076625c7400000001000000000000000100000008526f6f74
  504f4100000000080000000100000000140000000000000200000001000000200000000000010001
  00000002050100010001002000010109000000010001010000000026000000020002
>>Hi, neohope !
>>150

Java实现CORBA静态绑定(二)

本文主要内容涉及:

  • CORBA基本架构
  • IDL文件编写
  • POA示例实现
  • POA+TIE示例实现
  • ImplBase示例实现
  • ImplBase+TIE示例实现
  • Persistent示例实现

要写一个静态绑定的CORBA程序,首先要完成的就是定义接口。CORBA采用的接口描述方式为IDL(Interface Description Language),IDL的语法规则类似于CPP,所以Java的类型需要做类型映射。常见类型映射关系如下:

IDL Type Java Type
module package
boolean boolean
char, wchar char
octet byte
string, wstring java.lang.String
short, unsigned short short
long, unsigned long int
long long, unsigned long long long
float float
double double
fixed java.math.BigDecimal
enum, struct, union class
sequence, array array
interface (non-abstract) signature interface and an operations interface, helper class, holder class
interface (abstract) signature interface, helper class, holder class
constant (not within an interface) public interface
constant (within an interface) fields in the Java signature interface for non-abstract, or the sole Java interface for abstract
exception class
Any org.omg.CORBA.Any
type declarations nested within interfaces “scoped” package
typedef helper classes
pseudo objects pseudo interface
readonly attribute accessor method
readwrite attribute accessor and modifer methods
operation method

现在,写一个很简单的IDL文件:
hi.idl

module HiCorba
{
	interface Hi
	{
		string sayHiTo(in string someone);
		long add(in long numa, in long numb);
		oneway void shutdown();
	};
};

Java实现CORBA静态绑定(一)

本文主要内容涉及:

  • CORBA基本架构
  • IDL文件编写
  • POA示例实现
  • POA+TIE示例实现
  • ImplBase示例实现
  • ImplBase+TIE示例实现
  • Persistent示例实现

CORBA(Common Object Request Broker Architecture),即公用对象请求代理程序体系结构,是一种为解决分布式处理环境中硬件和软件系统的互连而提出的一种解决方案。其基本架构如下:

Object Services,即对象服务,是为使用和实现对象而提供的基本对象集合,这些服务应独立于应用领域。主要的CORBA服务有:名录服务(Naming Service)、事件服务(Event Service)、生命周期服务(Life Cycle Service)、关系服务(Relationship Service)以及事务服务(Transaction Service)等。这些服务几乎包括分布系统和面向对象系统的各个方面,每个组成部分都非常复杂。

IDL(Interface Description Language),即接口定义语言,是用来描述软件组件接口的一种规范语言。用户可以定义模块、接口、属性、方法、输入输出参数,甚至异常等等。IDL在不同的语言下都有相应的实现,可以把IDL描述的接口编译为目标语言,包括客户端代理和服务器端框架,以及相应的帮助类等等。比如Java中提供过了idlj命令用来编译。

ORB(Object Request Broker),即对象请求代理,是一个中间件,在对象间建立客户-服务器的关系。通过 ORB,一个客户可以很简单地使用服务器对象的方法而不论服务器是在同一机器上还是通过一个网络访问。ORB 截获调用然后负责找到一个对象实现这个请求,传递参数和方法,最后返回结果。客户不用知道对象在哪里,是什么语言实现的,他的操作系统以及其他和对象接口无关的东西。

CORBA按接口绑定方式,分为两大类,一类为动态绑定,一类为静态绑定。这里主要讲的是静态绑定。
在静态绑定时,客户端需要实现IDL Stubs,服务端需要实现IDL Skeleton。
在静态绑定中,CORBA在服务端实现IDL接口有两种方式,一种为继承模式(分为标准模式POA及兼容模式ImplBase),另一种为为委托模式(分为标准模式POA/Tie及兼容模式ImplBase/Tie)。各模式的区别主要在于生成IDL代码时,输入的参数不同,从而生成的接口不同,实现方式也略有区别。这里主要讲的为标准模式。

一次典型的CORBA调用,流程如下图所示:

GIOP(General Inter-ORB Protocol),即通用对象请求代理间通信协,提供了一个标准传输语法(低层数据表示方法)和ORB之间通信的信息格式集。GIOP只能用在ORB与ORB之间,而且,只能在符合理想条件的面向连接传输协议中使用。它不需要使用更高一层的RPC机制。这个协议是简单的(尽可能简单,但不是简单化),可升级的,使用方便。它被设计为可移动的、高效能的表现、较少依靠其它的低层传输协议。当然,由于不同传输使用不同版本的GIOP,它们可能不能直接协作工作,但它能很容易的连接网络域。

IIOP (Internet Inter-ORB Protocol),即Internet对象代理间通信协议,指出如何通过TCP/IP连接交换GIOP信息。IIOP为Internet提供了一个标准的协作工作协议,它使兼容的ORB能基于现在流行的协议和产品进行“out of the box”方式的协作工作。它也能被用于两个半桥(half-bridges )之间的协议。该协议能用于任何ORB与IP(Internet Protocol)域之间的协作工作,除非ORB选择了特殊的协议。这时,它是TCP/IP环境下基本的inter-ORB 协议,最普遍的传输层。

GIOP 不基于任何特别的网络协议,OMG 在最广泛使用的通信传输平台 — TCP/IP 上标准化 GIOP,GIOP 加 TCP/IP 等于 IIOP。

DBUS发送接收数据(下)

1、编译后,由于没有进行配置,默认是无法运行的。
为了可以正常运行,增加或修改下面的配置文件即可。
/etc/dbus-1.0/system-local.conf

<!-- This configuration file controls the systemwide message bus.
     Add a system-local.conf and edit that rather than changing this 
     file directly. -->

<!-- Note that there are any number of ways you can hose yourself
     security-wise by screwing up this file; in particular, you
     probably don't want to listen on any more addresses, add any more
     auth mechanisms, run as a different user, etc. -->

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>

  <!-- Our well-known bus type, do not change this -->
  <type>system</type>

  <!-- Run as special user -->
  <user>messagebus</user>

  <!-- Fork into daemon mode -->
  <fork/>

  <!-- We use system service launching using a helper -->
  <standard_system_servicedirs/>

  <!-- This is a setuid helper that is used to launch system services -->
  <servicehelper>/usr/lib/dbus-1.0/dbus-daemon-launch-helper</servicehelper>

  <!-- Write a pid file -->
  <pidfile>/var/run/dbus/pid</pidfile>

  <!-- Enable logging to syslog -->
  <syslog/>

  <!-- Only allow socket-credentials-based authentication -->
  <auth>EXTERNAL</auth>

  <!-- Only listen on a local socket. (abstract=/path/to/socket 
       means use abstract namespace, don't really create filesystem 
       file; only Linux supports this. Use path=/whatever on other 
       systems.) -->
  <listen>unix:path=/var/run/dbus/system_bus_socket</listen>

  <policy context="default">
    <!-- All users can connect to system bus -->
    <allow user="*"/>

    <!-- Holes must be punched in service configuration files for
         name ownership and sending method calls -->
    <allow own="*"/>
    <allow send_type="method_call"/>

    <!-- Signals and reply messages (method returns, errors) are allowed
         by default -->
    <allow send_type="signal"/>
    <allow send_requested_reply="true" send_type="method_return"/>
    <allow send_requested_reply="true" send_type="error"/>

    <!-- All messages may be received by default -->
    <allow receive_type="method_call"/>
    <allow receive_type="method_return"/>
    <allow receive_type="error"/>
    <allow receive_type="signal"/>

    <!-- Allow anyone to talk to the message bus -->
    <allow send_destination="org.freedesktop.DBus"/>
    <!-- But disallow some specific bus services -->
    <deny send_destination="org.freedesktop.DBus"
          send_interface="org.freedesktop.DBus"
          send_member="UpdateActivationEnvironment"/>
    <deny send_destination="org.freedesktop.DBus"
          send_interface="org.freedesktop.systemd1.Activator"/>
  </policy>

  <!-- Only systemd, which runs as root, may report activation failures. -->
  <policy user="root">
    <allow send_destination="org.freedesktop.DBus"
           send_interface="org.freedesktop.systemd1.Activator"/>
  </policy>

  <!-- Config files are placed here that among other things, punch 
       holes in the above policy for specific services. -->
  <includedir>system.d</includedir>

  <include if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include>

</busconfig>

2、测试消息发送
服务端:

$./testdbus_s.bin receive
Listening for signals
Match rule sent
Got Signal with value: Hello
Got Signal with value: Hi
Bye......

客户端:

$./testdbus_s.bin send Hello
Sending signal with value: Hello
Signal Sent

$./testdbus_s.bin send Hi
Sending signal with value: Hi
Signal Sent

$./testdbus_s.bin send Bye
Sending signal with value: Bye
Signal Sent

3、测试方法调用
服务端:

$./testdbus_s.bin listen
Listening for method calls
Method Invoked with value: Hello
Method Invoked with value: Hi
Bye......

客户端:

$./testdbus_s.bin query Hello
Calling remote method with Hello
Request Sent
Got Reply: 1, 21614

$./testdbus_s.bin query Hi
Calling remote method with Hi
Request Sent
Got Reply: 1, 21614

$./testdbus_s.bin query Bye
Calling remote method with Bye
Request Sent
Got Reply: 1, 21614

DBUS发送接收数据(上)

1、Server端
testdbus_s.c

#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

/**
 * Wait for signals on the bus and reply
 */
void receive()
{
  DBusMessage* msg;
  DBusMessageIter args;
  DBusConnection* conn;
  DBusError err;
  int ret;
  char* sigvalue;
  int loop=1;

  printf("Listening for signals\n");

  // initialise the errors
  dbus_error_init(&err);
  
  // connect to the bus and check for errors
  conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Connection Error (%s)\n", err.message);
     dbus_error_free(&err); 
  }
  if (NULL == conn) { 
     exit(1);
  }
  
  // request our name on the bus and check for errors
  ret = dbus_bus_request_name(conn, "neohope.dbus.signal.target", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Name Error (%s)\n", err.message);
     dbus_error_free(&err); 
  }
  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
     exit(1);
  }

  // add a rule for which messages we want to see
  dbus_bus_add_match(conn, "type='signal',interface='neohope.dbus.signal.Type'", &err); // see signals from the given interface
  dbus_connection_flush(conn);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Match Error (%s)\n", err.message);
     exit(1); 
  }
  printf("Match rule sent\n");

  // loop listening for signals being emmitted
  while (loop) {

     // non blocking read of the next available message
     dbus_connection_read_write(conn, 0);
     msg = dbus_connection_pop_message(conn);

     // loop again if we haven't read a message
     if (NULL == msg) { 
        sleep(1);
        continue;
     }

     // check if the message is a signal from the correct interface and with the correct name
     if (dbus_message_is_signal(msg, "neohope.dbus.signal.Type", "TestSignal")) {
        
        // read the parameters
        if (!dbus_message_iter_init(msg, &args))
           fprintf(stderr, "Message Has No Parameters\n");
        else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) 
           fprintf(stderr, "Argument is not string!\n"); 
        else
           dbus_message_iter_get_basic(&args, &sigvalue);
        
        if(strcmp("Bye",sigvalue)==0) {
           loop = 0;
           printf("Bye......\n");
        }
        else {
          printf("Got Signal with value: %s\n", sigvalue);
        }
     }

     // free the message
     dbus_message_unref(msg);
  }
  // do not close the connection
  // dbus_connection_close(conn);
}

/**
 * Deal with remote method call 
 */
int reply_to_method_call(DBusMessage* msg, DBusConnection* conn)
{
  DBusMessage* reply;
  DBusMessageIter args;
  int stat = 1;
  int ret = 1;
  dbus_uint32_t level = 21614;
  dbus_uint32_t serial = 0;
  char* param = "";

  // read the arguments
  if (!dbus_message_iter_init(msg, &args))
     fprintf(stderr, "Message has no arguments!\n"); 
  else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) 
     fprintf(stderr, "Argument is not string!\n"); 
  else 
     dbus_message_iter_get_basic(&args, &param);

  if(strcmp("Bye",param)==0){
    ret = 0;
    printf ("Bye......\n");
  }
  else {
    printf("Method Invoked with value: %s\n", sigvalue);
  }

  // create a reply from the message
  reply = dbus_message_new_method_return(msg);

  // add the arguments to the reply
  dbus_message_iter_init_append(reply, &args);
  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &stat)) { 
     fprintf(stderr, "Out Of Memory!\n"); 
     exit(1);
  }
  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &level)) { 
     fprintf(stderr, "Out Of Memory!\n"); 
     exit(1);
  }

  // send the reply && flush the connection
  if (!dbus_connection_send(conn, reply, &serial)) {
     fprintf(stderr, "Out Of Memory!\n"); 
     exit(1);
  }
  dbus_connection_flush(conn);

  // free the reply
  dbus_message_unref(reply);
  
  return ret;
}

/**
 * Server that exposes a method call and waits for it to be called
 */
void listen() 
{
  DBusMessage* msg;
  DBusMessage* reply;
  DBusMessageIter args;
  DBusConnection* conn;
  DBusError err;
  int loop = 1;
  int ret;
  char* param;

  printf("Listening for method calls\n");

  // initialise the error
  dbus_error_init(&err);
  
  // connect to the bus and check for errors
  conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Connection Error (%s)\n", err.message); 
     dbus_error_free(&err); 
  }
  if (NULL == conn) {
     fprintf(stderr, "Connection Null\n"); 
     exit(1); 
  }
  
  // request our name on the bus and check for errors
  ret = dbus_bus_request_name(conn, "neohope.dbus.method.provider", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Name Error (%s)\n", err.message); 
     dbus_error_free(&err);
  }
  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
     fprintf(stderr, "Not Primary Owner (%d)\n", ret);
     exit(1); 
  }

  // loop, testing for new messages
  while (loop) {
     // non blocking read of the next available message
     dbus_connection_read_write(conn, 0);
     msg = dbus_connection_pop_message(conn);

     // loop again if we haven't got a message
     if (NULL == msg) { 
        sleep(1); 
        continue; 
     }
     
     // check this is a method call for the right interface & method
     if (dbus_message_is_method_call(msg, "neohope.dbus.method.Type", "TestMethod")) 
        loop = reply_to_method_call(msg, conn);

     // free the message
     dbus_message_unref(msg);
  }

  // do not close the connection
  // dbus_connection_close(conn);
}

int main(int argc, char** argv)
{
  if (2 > argc) {
     printf ("Syntax: testdbus_s [receive|listen] [<param>]\n");
     return 1;
  }
  char* param = "no param";
  if (3 >= argc && NULL != argv[2]) param = argv[2];

  if (0 == strcmp(argv[1], "receive"))
     receive();
  else if (0 == strcmp(argv[1], "listen"))
     listen();
  else {
     printf ("Syntax: testdbus_s [receive|listen] [<param>]\n");
     return 1;
  }
  return 0;
}

2、Client端
testdbus_c.c

#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

/**
 * Connect to the DBUS bus and send a broadcast signal
 */
void sendsignal(char* sigvalue)
{
  DBusMessage* msg;
  DBusMessageIter args;
  DBusConnection* conn;
  DBusError err;
  int ret;
  dbus_uint32_t serial = 0;

  printf("Sending signal with value: %s\n", sigvalue);

  // initialise the error value
  dbus_error_init(&err);

  // connect to the DBUS system bus, and check for errors
  conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Connection Error (%s)\n", err.message); 
     dbus_error_free(&err); 
  }
  if (NULL == conn) { 
     exit(1); 
  }

  // register our name on the bus, and check for errors
  ret = dbus_bus_request_name(conn, "neohope.dbus.signal.source", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Name Error (%s)\n", err.message); 
     dbus_error_free(&err); 
  }
  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
     exit(1);
  }

  // create a signal & check for errors 
  msg = dbus_message_new_signal("/neohope/dbus/signal/Object", // object name of the signal
                                "neohope.dbus.signal.Type", // interface name of the signal
                                "TestSignal"); // name of the signal
  if (NULL == msg) 
  { 
     fprintf(stderr, "Message Null\n"); 
     exit(1); 
  }

  // append arguments onto signal
  dbus_message_iter_init_append(msg, &args);
  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &sigvalue)) {
     fprintf(stderr, "Out Of Memory!\n"); 
     exit(1);
  }

  // send the message and flush the connection
  if (!dbus_connection_send(conn, msg, &serial)) {
     fprintf(stderr, "Out Of Memory!\n"); 
     exit(1);
  }
  dbus_connection_flush(conn);
  
  printf("Signal Sent\n");
  
  // free the message
  dbus_message_unref(msg);
  // do not close the connection
  // dbus_connection_close(conn);
}

/**
 * Call a method on a remote object
 */
void query(char* param) 
{
  DBusMessage* msg;
  DBusMessageIter args;
  DBusConnection* conn;
  DBusError err;
  DBusPendingCall* pending;
  int ret;
  int stat;
  dbus_uint32_t level;

  printf("Calling remote method with %s\n", param);

  // initialiset the errors
  dbus_error_init(&err);

  // connect to the system bus and check for errors
  conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Connection Error (%s)\n", err.message); 
     dbus_error_free(&err);
  }
  if (NULL == conn) { 
     exit(1); 
  }

  // request our name on the bus
  ret = dbus_bus_request_name(conn, "neohope.dbus.method.caller", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
  if (dbus_error_is_set(&err)) { 
     fprintf(stderr, "Name Error (%s)\n", err.message); 
     dbus_error_free(&err);
  }
  if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { 
     exit(1);
  }

  // create a new method call and check for errors
  msg = dbus_message_new_method_call("neohope.dbus.method.provider", // target for the method call
                                     "/neohope/dbus/method/Object", // object to call on
                                     "neohope.dbus.method.Type", // interface to call on
                                     "TestMethod"); // method name
  if (NULL == msg) { 
     fprintf(stderr, "Message Null\n");
     exit(1);
  }

  // append arguments
  dbus_message_iter_init_append(msg, &args);
  if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {
     fprintf(stderr, "Out Of Memory!\n"); 
     exit(1);
  }
  
  // send message and get a handle for a reply
  if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) { // -1 is default timeout
     fprintf(stderr, "Out Of Memory!\n"); 
     exit(1);
  }
  if (NULL == pending) { 
     fprintf(stderr, "Pending Call Null\n"); 
     exit(1); 
  }
  dbus_connection_flush(conn);
  
  printf("Request Sent\n");
  
  // free message
  dbus_message_unref(msg);
  
  // block until we recieve a reply
  dbus_pending_call_block(pending);

  // get the reply message
  msg = dbus_pending_call_steal_reply(pending);
  if (NULL == msg) {
     fprintf(stderr, "Reply Null\n"); 
     exit(1); 
  }
  // free the pending message handle
  dbus_pending_call_unref(pending);

  // read the parameters
  if (!dbus_message_iter_init(msg, &args))
     fprintf(stderr, "Message has no arguments!\n"); 
  else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args)) 
     fprintf(stderr, "Argument is not boolean!\n"); 
  else
     dbus_message_iter_get_basic(&args, &stat);

  if (!dbus_message_iter_next(&args))
     fprintf(stderr, "Message has too few arguments!\n"); 
  else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)) 
     fprintf(stderr, "Argument is not int!\n"); 
  else
     dbus_message_iter_get_basic(&args, &level);

  printf("Got Reply: %d, %d\n", stat, level);
  
  // free reply and close connection
  dbus_message_unref(msg);   
  //dbus_connection_close(conn);
}

int main(int argc, char** argv)
{
  if (2 > argc) {
     printf ("Syntax: testdbus_c [send|query] [<param>]\n");
     return 1;
  }
  char* param = "no param";
  if (3 >= argc && NULL != argv[2]) param = argv[2];

  if (0 == strcmp(argv[1], "send"))
     sendsignal(param);
  else if (0 == strcmp(argv[1], "query"))
     query(param);
  else {
     printf ("Syntax: testdbus_c [send|query] [<param>]\n");
     return 1;
  }
  return 0;
}

3、Makefile

CC=gcc
LDFLAGS+=-ldbus-1
CFLAGS+=-I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/

all:testdbus_c.bin testdbus_s.bin

testdbus_c.bin:testdbus_c.o
	$(CC) $(LDFLAGS) -o testdbus_c.bin testdbus_c.o 

testdbus_c.o:testdbus_c.c
	$(CC) $(CFLAGS) -c -o testdbus_c.o testdbus_c.c 

testdbus_s.bin:testdbus_s.o
	$(CC) $(LDFLAGS) -o testdbus_s.bin testdbus_s.o 

testdbus_s.o:testdbus_s.c
	$(CC) $(CFLAGS) -c -o testdbus_s.o testdbus_s.c 

clean:
	rm *.o *.bin

4、编译

make

NIO多端口监听

1、NIOServerTest.java

package com.neohope.multisocket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class NIOServerTest {
    public static void StartSockets() throws IOException {
        Selector selector = Selector.open();

        int[] ports = {4000, 4001, 4002};
        for (int port : ports) {
            ServerSocketChannel server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.socket().bind(new InetSocketAddress(port));
            //只处理了建立连接的消息
            server.register(selector, SelectionKey.OP_ACCEPT);
        }

        int serverPort = 0;
        ByteBuffer byteBuffer = null;
        ServerSocketChannel serverChannel = null;
        SocketChannel clientChannel = null;
        while (selector.isOpen()) {
            selector.select();
            Set<SelectionKey> readyKeys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = readyKeys.iterator();
            while (keyIterator.hasNext()) {
                SelectionKey selectedKey = keyIterator.next();
                keyIterator.remove();
                if (selectedKey.isAcceptable()) {
                    serverChannel = (ServerSocketChannel) selectedKey.channel();
                    serverPort = serverChannel.socket().getLocalPort();
                    clientChannel = serverChannel.accept();
                    clientChannel.configureBlocking(false);
                    switch (serverPort) {
                        case 4000:
                            byteBuffer=ByteBuffer.wrap("welcome to port 4000".getBytes(Charset.forName("UTF-8")));
                            clientChannel.write(byteBuffer);
                            break;
                        case 4001:
                            byteBuffer=ByteBuffer.wrap("welcome to port 4001".getBytes(Charset.forName("UTF-8")));
                            clientChannel.write(byteBuffer);
                            break;
                        case 4002:
                            byteBuffer=ByteBuffer.wrap("welcome to port 4002".getBytes(Charset.forName("UTF-8")));
                            clientChannel.write(byteBuffer);
                            break;
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        StartSockets();
    }
}

2、NIOClientTest.java

package com.neohope.multisocket;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOClientTest {
    public static void StartClient(String host, int port)
    {
        int readSize = 0;
        SocketChannel clientChannel = null;
        SocketAddress socketAddress = new InetSocketAddress(host, port);
        byte[] bytes;
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            clientChannel = SocketChannel.open();
            clientChannel.connect(socketAddress);
            try {
                while ((readSize = clientChannel.read(byteBuffer)) >= 0) {
                    byteBuffer.flip();
                    bytes = new byte[readSize];
                    byteBuffer.get(bytes);
                    byteArrayOutputStream.write(bytes);
                    byteBuffer.clear();
                    //服务端没有主动关闭连接,读取少于1024,假设读取完毕
                    if(readSize<1024)break;
                }
                System.out.println(byteArrayOutputStream.toString());
            } catch (IOException ex) {
                ex.printStackTrace();
            } finally {
                try {
                    byteArrayOutputStream.close();
                } catch(Exception ex) {}
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                clientChannel.close();
            } catch(Exception ex) {}
        }
    }

    public static void main(String[] args) throws IOException {
        StartClient("localhost",4000);
        StartClient("localhost",4001);
        StartClient("localhost",4002);
    }
}

PPT2ANY转换工具

PPT2ANY.vbs

Option Explicit

PPT2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.pptx","PATH_TO_INFILE\NEOHOPE.COM.OUT.pdf","PDF"
PPT2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.pptx","PATH_TO_INFILE\NEOHOPE.COM.OUT.png","PNG"

Sub PPT2ANY( inFile, outFile, outFormat)
	Dim objFSO, objPPT, objPresentation, pptFormat

	Const ppSaveAsAddIn                             =8
	Const ppSaveAsBMP                               =19
	Const ppSaveAsDefault                           =11
	Const ppSaveAsEMF                               =23
	Const ppSaveAsExternalConverter                 =64000
	Const ppSaveAsGIF                               =16
	Const ppSaveAsJPG                               =17
	Const ppSaveAsMetaFile                          =15
	Const ppSaveAsMP4                               =39
	Const ppSaveAsOpenDocumentPresentation          =35
	Const ppSaveAsOpenXMLAddin                      =30
	Const ppSaveAsOpenXMLPicturePresentation        =36
	Const ppSaveAsOpenXMLPresentation               =24
	Const ppSaveAsOpenXMLPresentationMacroEnabled   =25
	Const ppSaveAsOpenXMLShow                       =28
	Const ppSaveAsOpenXMLShowMacroEnabled           =29
	Const ppSaveAsOpenXMLTemplate                   =26
	Const ppSaveAsOpenXMLTemplateMacroEnabled       =27
	Const ppSaveAsOpenXMLTheme                      =31
	Const ppSaveAsPDF                               =32
	Const ppSaveAsPNG                               =18
	Const ppSaveAsPresentation                      =1
	Const ppSaveAsRTF                               =6
	Const ppSaveAsShow                              =7
	Const ppSaveAsStrictOpenXMLPresentation         =38
	Const ppSaveAsTemplate                          =5
	Const ppSaveAsTIF                               =21
	Const ppSaveAsWMV                               =37
	Const ppSaveAsXMLPresentation                   =34
	Const ppSaveAsXPS                               =33

	' Create a File System object
	Set objFSO = CreateObject( "Scripting.FileSystemObject" )

	' Create a PowerPoint object
	Set objPPT = CreateObject( "PowerPoint.Application" )

	With objPPT
		' True: make PowerPoint visible; False: invisible
		.Visible = True
 
		' Check if the PowerPoint document exists
		If not( objFSO.FileExists( inFile ) ) Then
			WScript.Echo "FILE OPEN ERROR: The file does not exist" & vbCrLf
			' Close PowerPoint
			.Quit
			Exit Sub
		End If
 
		' Open the PowerPoint document
		.Presentations.Open inFile
 
		' Make the opened file the active document
		Set objPresentation = .ActivePresentation
 
		If StrComp(Ucase( outFormat ),"PDF") = 0 then
			pptFormat = ppSaveAsPDF 
		ElseIf StrComp(Ucase( outFormat ),"XPS") = 0 then
			pptFormat = ppSaveAsXPS
		ElseIf StrComp(Ucase( outFormat ),"BMP") = 0 then
			pptFormat= ppSaveAsBMP
		ElseIf StrComp(Ucase( outFormat ),"PNG") = 0 then
			pptFormat= ppSaveAsPNG
		ElseIf StrComp(Ucase( outFormat ),"JPG") = 0 then
			pptFormat= ppSaveAsJPG
		ElseIf StrComp(Ucase( outFormat ),"GIF") = 0 then
			pptFormat= ppSaveAsGIF
		ElseIf StrComp(Ucase( outFormat ),"XML") = 0 then
			pptFormat= ppSaveAsOpenXMLPresentation
		ElseIf StrComp(Ucase( outFormat ),"RTF") = 0 then
			pptFormat= ppSaveAsRTF
		Else
			WScript.Echo "FILE FORTMART ERROR: Unknown file format" & vbCrLf
			' Close PowerPoint
			.Quit
			Exit Sub
		End If

		' Save in PDF/XPS format
		objPresentation.SaveAs outFile, pptFormat
 
		' Close the active document
		objPresentation.Close
 
		' Close PowerPoint
		.Quit
	End With
End Sub

Excel2ANY转换工具

Excel2ANY.vbs

Option Explicit

Excel2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.xlsx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.pdf","PDF"
Excel2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.xlsx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.xps","XPS"
Excel2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.xlsx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.csv","CSV"

Private Sub Excel2ANY(inFile, outFile, outFormat)
	Dim objFSO, objExcel, objWorkbook, objSheet, xlFormat, isSaveAs

	Const xlAddIn                           =18
	Const xlAddIn8                          =18
	Const xlCSV                             =6
	Const xlCSVMac                          =22
	Const xlCSVMSDOS                        =24
	Const xlCSVWindows                      =23
	Const xlCurrentPlatformText             =-4158
	Const xlDBF2                            =7
	Const xlDBF3                            =8
	Const xlDBF4                            =11
	Const xlDIF                             =9
	Const xlExcel12                         =50
	Const xlExcel2                          =16
	Const xlExcel2FarEast                   =27
	Const xlExcel3                          =29
	Const xlExcel4                          =33
	Const xlExcel4Workbook                  =35
	Const xlExcel5                          =39
	Const xlExcel7                          =39
	Const xlExcel8                          =56
	Const xlExcel9795                       =43
	Const xlHtml                            =44
	Const xlIntlAddIn                       =26
	Const xlIntlMacro                       =25
	Const xlOpenDocumentSpreadsheet         =60
	Const xlOpenXMLAddIn                    =55
	Const xlOpenXMLStrictWorkbook           =61 
	Const xlOpenXMLTemplate                 =54
	Const xlOpenXMLTemplateMacroEnabled     =53
	Const xlOpenXMLWorkbook                 =51
	Const xlOpenXMLWorkbookMacroEnabled     =52
	Const xlSYLK                            =2
	Const xlTemplate                        =17
	Const xlTemplate8                       =17
	Const xlTextMac                         =19
	Const xlTextMSDOS                       =21
	Const xlTextPrinter                     =36
	Const xlTextWindows                     =20
	Const xlUnicodeText                     =42
	Const xlWebArchive                      =45
	Const xlWJ2WD1                          =14
	Const xlWJ3                             =40
	Const xlWJ3FJ3                          =41
	Const xlWK1                             =5
	Const xlWK1ALL                          =31
	Const xlWK1FMT                          =30
	Const xlWK3                             =15
	Const xlWK3FM3                          =32
	Const xlWK4                             =38
	Const xlWKS                             =4
	Const xlWorkbookDefault                 =51
	Const xlWorkbookNormal                  =-4143
	Const xlWorks2FarEast                   =28
	Const xlWQ1                             =34
	Const xlXMLSpreadsheet                  =46
	Const XlFixedFormatType_xlTypePDF       =0
	Const XlFixedFormatType_xlTypeXPS       =1

	' Create a File System object
	Set objFSO = CreateObject( "Scripting.FileSystemObject" )

	' Create a Excell object
	Set objExcel = CreateObject("Excel.Application")

	With objExcel
		' True: make Excell visible; False: invisible
		.Visible = True
 
		' Check if the Excell document exists
		If not( objFSO.FileExists( inFile ) ) Then
			WScript.Echo "FILE OPEN ERROR: The file does not exist" & vbCrLf
			' Close Excell
			.Quit
			Exit Sub
		End If
 
		' Open the Excell document
		.Workbooks.Open inFile
 
		' Make the opened file the active document
		Set objWorkbook = .ActiveWorkbook
		Set objSheet = .ActiveSheet

 		isSaveAs = True
		If StrComp(Ucase( outFormat ),"PDF") = 0 then
			isSaveAs = False
		ElseIf StrComp(Ucase( outFormat ),"XPS") = 0 then
			isSaveAs = False
		ElseIf StrComp(Ucase( outFormat ),"CSV") = 0 then
			xlFormat= xlCSV
		ElseIf StrComp(Ucase( outFormat ),"HTML") = 0 then
			xlFormat= xlHtml
		ElseIf StrComp(Ucase( outFormat ),"XML") = 0 then
			xlFormat= xlXMLSpreadsheet
		ElseIf StrComp(Ucase( outFormat ),"TXT") = 0 then
			xlFormat= xlTextWindows
		Else
			WScript.Echo "FILE FORTMART ERROR: Unknown file format" & vbCrLf
			' Close Excell
			.Quit
			Exit Sub
		End If

		' Save in PDF/XPS format
		If isSaveAs then
			objSheet.SaveAs outFile, xlFormat
		ElseIf StrComp(Ucase( outFormat ),"PDF") = 0 then
			objSheet.ExportAsFixedFormat XlFixedFormatType_xlTypePDF, outFile
		ElseIf StrComp(Ucase( outFormat ),"XPS") = 0 then
			objSheet.ExportAsFixedFormat XlFixedFormatType_xlTypeXPS, outFile
		End If
 
		' Close the active document
		objWorkbook.Close
 
		' Close Excell
		.Quit
	End With
End Sub

Word2ANY转换工具

Word2ANY.vbs

Option Explicit

Word2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.docx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.xps","XPS"
Word2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.docx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.PDF","PDF"
Word2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.docx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.HTML","HTML"
Word2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.docx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.XML","XML"
Word2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.docx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.RTF","RTF"
Word2ANY "PATH_TO_INFILE\NEOHOPE.COM.IN.docx","PATH_TO_OUTFILE\NEOHOPE.COM.OUT.TXT","TEXT"

Sub Word2ANY( inFile, outFile, outFormat)
	Dim objFSO, objWord, objDoc, wdFormat

	Const wdFormatDocument                    =  0
	Const wdFormatDocument97                  =  0
	Const wdFormatDocumentDefault             = 16
	Const wdFormatDOSText                     =  4
	Const wdFormatDOSTextLineBreaks           =  5
	Const wdFormatEncodedText                 =  7
	Const wdFormatFilteredHTML                = 10
	Const wdFormatFlatXML                     = 19
	Const wdFormatFlatXMLMacroEnabled         = 20
	Const wdFormatFlatXMLTemplate             = 21
	Const wdFormatFlatXMLTemplateMacroEnabled = 22
	Const wdFormatHTML                        =  8
	Const wdFormatPDF                         = 17
	Const wdFormatRTF                         =  6
	Const wdFormatTemplate                    =  1
	Const wdFormatTemplate97                  =  1
	Const wdFormatText                        =  2
	Const wdFormatTextLineBreaks              =  3
	Const wdFormatUnicodeText                 =  7
	Const wdFormatWebArchive                  =  9
	Const wdFormatXML                         = 11
	Const wdFormatXMLDocument                 = 12
	Const wdFormatXMLDocumentMacroEnabled     = 13
	Const wdFormatXMLTemplate                 = 14
	Const wdFormatXMLTemplateMacroEnabled     = 15
	Const wdFormatXPS                         = 18

	' Create a File System object
	Set objFSO = CreateObject( "Scripting.FileSystemObject" )

	' Create a Word object
	Set objWord = CreateObject( "Word.Application" )

	With objWord
		' True: make Word visible; False: invisible
		.Visible = True
 
		' Check if the Word document exists
		If not( objFSO.FileExists( inFile ) ) Then
			WScript.Echo "FILE OPEN ERROR: The file does not exist" & vbCrLf
			' Close Word
			.Quit
			Exit Sub
		End If
 
		' Open the Word document
		.Documents.Open inFile
 
		' Make the opened file the active document
		Set objDoc = .ActiveDocument
 
		If StrComp(Ucase( outFormat ),"PDF") = 0 then
			wdFormat = wdFormatPDF 
		ElseIf StrComp(Ucase( outFormat ),"XPS") = 0 then
			wdFormat = wdFormatXPS
		ElseIf StrComp(Ucase( outFormat ),"TXT") = 0 then
			wdFormat= wdFormatTEXT
		ElseIf StrComp(Ucase( outFormat ),"HTML") = 0 then
			wdFormat= wdFormatHTML
		ElseIf StrComp(Ucase( outFormat ),"XML") = 0 then
			wdFormat= wdFormatXML
		ElseIf StrComp(Ucase( outFormat ),"RTF") = 0 then
			wdFormat= wdFormatXML
		Else
			WScript.Echo "FILE FORTMART ERROR: Unknown file format" & vbCrLf
			' Close Word
			.Quit
			Exit Sub
		End If

		' Save in PDF/XPS format
		objDoc.SaveAs outFile, wdFormat
 
		' Close the active document
		objDoc.Close
 
		' Close Word
		.Quit
	End With
End Sub