在SWT中提供了访问OLE的方式,不过相关的例子都是进程内OLE的例子,比如嵌入浏览器、引用ActiveX控件什么的。由于客户的需求,我们需要在程序中通过进程外Automation服务的方式访问IE浏览器。经过网上搜寻,找到一个朋友写的CComObject类可以访问Automation服务。不过经过使用发现一些错误,因此对其进行了修改,为了方便访问IE,我又封装了一个IEAutomation类,这样就暴露给使用者navigate、quit这样的方法。(作者:www.cownew.com 杨中科)
这里例子完全可以用来操控其他的Automation对象,比如操控Work、Excel、AcrobatReader等。
全部代码如下:
CComObject.java
package test;


import org.eclipse.swt.SWT;

import org.eclipse.swt.internal.ole.win32.COM;

import org.eclipse.swt.internal.ole.win32.DISPPARAMS;

import org.eclipse.swt.internal.ole.win32.EXCEPINFO;

import org.eclipse.swt.internal.ole.win32.GUID;

import org.eclipse.swt.internal.ole.win32.IDispatch;

import org.eclipse.swt.internal.ole.win32.ITypeInfo;

import org.eclipse.swt.internal.ole.win32.IUnknown;

import org.eclipse.swt.internal.win32.OS;

import org.eclipse.swt.ole.win32.OLE;

import org.eclipse.swt.ole.win32.Variant;


/** *//**

* @author hcw

*/

public class CComObject



{

private GUID guid = new GUID();


private IDispatch Autoface = null;


private ITypeInfo TypeInfo = null;


private void CreateComObject()



{

dispose();


int[] ppv = new int[1];


int ret = COM.CoCreateInstance(guid, 0, COM.CLSCTX_INPROC_SERVER

| COM.CLSCTX_LOCAL_SERVER, COM.IIDIUnknown, ppv);

if (ret != COM.S_OK)

OLE.error(ret);

// throw new RuntimeException("对象创建失败!");


IUnknown objIUnknown = new IUnknown(ppv[0]);

ppv = new int[1];


ret = objIUnknown.QueryInterface(COM.IIDIDispatch, ppv);

objIUnknown.Release();

if (ret != COM.S_OK)

OLE.error(ret);

// throw new RuntimeException("对象不支持Dispatch!");


Autoface = new IDispatch(ppv[0]);


ppv = new int[1];

ret = Autoface.GetTypeInfo(0, COM.LOCALE_USER_DEFAULT, ppv);

if (ret == OLE.S_OK)



{

TypeInfo = new ITypeInfo(ppv[0]);

TypeInfo.AddRef();


}


}


private int getIDsOfNames(String name)



{

int[] rgdispid = new int[1];


String[] names = new String[]
{ name };

int ret = Autoface.GetIDsOfNames(guid, names, names.length,

COM.LOCALE_USER_DEFAULT, rgdispid);

if (ret != COM.S_OK)

return -1;


return rgdispid[0];

}


private void getVariantData(Variant aVar, int pData)



{

if (pData == 0)

OLE.error(OLE.ERROR_OUT_OF_MEMORY);


COM.VariantInit(pData);


if ((aVar.getType() & COM.VT_BYREF) == COM.VT_BYREF)



{


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);


COM.MoveMemory(pData + 8, new int[]
{ aVar.getByRef() }, 4);

return;

}


switch (aVar.getType())



{

case COM.VT_EMPTY:

break;

case COM.VT_BOOL:


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);

COM.MoveMemory(pData + 8,


new int[]
{ (aVar.getBoolean()) ? COM.VARIANT_TRUE

: COM.VARIANT_FALSE }, 2);

break;

case COM.VT_R4:


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);


COM.MoveMemory(pData + 8, new float[]
{ aVar.getFloat() }, 4);

break;

case COM.VT_I4:


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);


COM.MoveMemory(pData + 8, new int[]
{ aVar.getInt() }, 4);

break;

case COM.VT_DISPATCH:

aVar.getDispatch().AddRef();


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);


COM.MoveMemory(pData + 8, new int[]
{ aVar.getDispatch()

.getAddress() }, 4);

break;

case COM.VT_UNKNOWN:

aVar.getUnknown().AddRef();


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);


COM.MoveMemory(pData + 8, new int[]
{ aVar.getUnknown()

.getAddress() }, 4);

break;

case COM.VT_I2:


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);


COM.MoveMemory(pData + 8, new short[]
{ aVar.getShort() }, 2);

break;

case COM.VT_BSTR:


COM.MoveMemory(pData, new short[]
{ aVar.getType() }, 2);

char[] data = (aVar.getString() + "\0").toCharArray();

int ptr = COM.SysAllocString(data);


COM.MoveMemory(pData + 8, new int[]
{ ptr }, 4);

break;


default:

OLE.error(SWT.ERROR_NOT_IMPLEMENTED);

}

}


private Variant setVariantData(int pData)



{

if (pData == 0)

OLE.error(OLE.ERROR_INVALID_ARGUMENT);


Variant ret = null;

short[] dataType = new short[1];

COM.MoveMemory(dataType, pData, 2);

int type = dataType[0];


if ((type & COM.VT_BYREF) == COM.VT_BYREF)



{

int[] newByRefPtr = new int[1];

OS.MoveMemory(newByRefPtr, pData + 8, 4);

return new Variant(newByRefPtr[0], COM.VT_BYREF);

}


switch (type)



{

case COM.VT_EMPTY:

break;

case COM.VT_BOOL:

short[] newBooleanData = new short[1];

COM.MoveMemory(newBooleanData, pData + 8, 2);

ret = new Variant(newBooleanData[0] != 0);

break;

case COM.VT_R4:

float[] newFloatData = new float[1];

COM.MoveMemory(newFloatData, pData + 8, 4);

ret = new Variant(newFloatData[0]);

break;

case COM.VT_I4:

int[] newIntData = new int[1];

OS.MoveMemory(newIntData, pData + 8, 4);

ret = new Variant(newIntData[0]);

break;

case COM.VT_DISPATCH:



{

int[] ppvObject = new int[1];

OS.MoveMemory(ppvObject, pData + 8, 4);

if (ppvObject[0] == 0)



{

type = COM.VT_EMPTY;

break;

}

ret = new Variant(new IDispatch(ppvObject[0]));

break;

}

case COM.VT_UNKNOWN:



{

int[] ppvObject = new int[1];

OS.MoveMemory(ppvObject, pData + 8, 4);

if (ppvObject[0] == 0)



{

type = COM.VT_EMPTY;

break;

}

ret = new Variant(new IUnknown(ppvObject[0]));

break;

}

case COM.VT_I2:

short[] newShortData = new short[1];

COM.MoveMemory(newShortData, pData + 8, 2);

ret = new Variant(newShortData[0]);

break;

case COM.VT_BSTR:

// get the address of the memory in which the string resides

int[] hMem = new int[1];

OS.MoveMemory(hMem, pData + 8, 4);

if (hMem[0] == 0)



{

type = COM.VT_EMPTY;

break;

}

int size = COM.SysStringByteLen(hMem[0]);

if (size > 0)



{

char[] buffer = new char[(size + 1) / 2]; // add one to avoid

// rounding errors

COM.MoveMemory(buffer, hMem[0], size);

ret = new Variant(new String(buffer));

} else



{

ret = new Variant(""); //$NON-NLS-1$

}

break;


default:

int newPData = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT,

Variant.sizeof);

if (COM.VariantChangeType(newPData, pData, (short) 0, COM.VT_R4) == COM.S_OK)


