Java and COM Automation by Kenneth Bandes Listing One javareg /register /class:autoXTest /clsid:"{735640F0-3B59-11D1-B5B9-98596A000000}" /typelib:autoXTest.tlb /progid:"autoXTest.Main" /codebase:"g:\projects\autoX" Listing Two [ object, uuid(4f9dfa91-32ef-11d1-b5ac-9e4a44000000), dual, pointer_default(unique), helpstring("Application Interface") ] interface Application : IDispatch { /* for Application, this just returns pointer to self */ [ propget, helpstring("Application property") ] HRESULT Application([out,retval] Application** val); /* Parent, i.e. containing object for Application, returns pointer to itself */ [ propget, helpstring("Parent property") ] HRESULT Parent([out,retval] Application** val); /* name of the application */ [ propget, id(DISPID_VALUE), helpstring("Application Name") ] HRESULT Name([out,retval] BSTR* val); /* the collection of open AddressBooks */ [ propget, helpstring("AddressBooks property") ] HRESULT AddressBooks([out,retval] AddressBooks** val); } Listing Three // Auto-generated using JActiveX.EXE 4.79.2207 // (JActiveX AddressBookLib.tlb) // WARNING: Do not remove the comments that include "@com" directives. // This source file must be compiled by a @com-aware compiler. // If you are using the Microsoft Visual J++ compiler, you must use // version 1.02.3920 or later. Previous versions will not issue an error // but will not generate COM-enabled class files. package addressbooklib; import com.ms.com.*; import com.ms.com.IUnknown; import com.ms.com.Variant; // Dual interface Application /** @com.interface(iid=4F9DFA91-32EF-11D1-B5AC-9E4A44000000, thread=AUTO, type=DUAL) */ public interface Application extends IUnknown { /** @com.method(vtoffset=4, dispid=1610743808, type=PROPGET, name="Application", addFlagsVtable=4) @com.parameters([iid=4F9DFA91-32EF-11D1-B5AC-9E4A44000000, thread=AUTO,type=DISPATCH] return) */ public addressbooklib.Application getApplication(); /** @com.method(vtoffset=5, dispid=1610743809, type=PROPGET, name="Parent", addFlagsVtable=4) @com.parameters([iid=4F9DFA91-32EF-11D1-B5AC-9E4A44000000,thread=AUTO, type=DISPATCH] return) */ public addressbooklib.Application getParent(); /** @com.method(vtoffset=6, dispid=0, type=PROPGET, name="Name", addFlagsVtable=4) @com.parameters([type=STRING] return) */ public String getName(); /** @com.method(vtoffset=7, dispid=1610743811, type=PROPGET, name="AddressBooks", addFlagsVtable=4) @com.parameters([iid=4F9DFA96-32EF-11D1-B5AC-9E4A44000000, thread=AUTO,type=DISPATCH] return) */ public addressbooklib.AddressBooks getAddressBooks(); public static final com.ms.com._Guid iid = new com.ms.com._Guid((int)0x4f9dfa91, (short)0x32ef, (short)0x11d1, (byte)0xb5, (byte)0xac, (byte)0x9e, (byte)0x4a, (byte)0x44, (byte)0x0, (byte)0x0, (byte)0x0); } Listing Four [ uuid(4f9dfa95-32ef-11d1-b5ac-9e4a44000000), appobject, // the Application object helpstring("The Application Object for the AddressBook API") ] coclass CApplication { interface Application; }; Listing Five [ object, uuid(4f9dfa92-32ef-11d1-b5ac-9e4a44000000), dual, pointer_default(unique), helpstring("AddressBook Interface") ] interface AddressBook : IDispatch { [ propget, helpstring("Application property") ] HRESULT Application([out,retval] Application** val); [ propget, helpstring("Parent property") ] HRESULT Parent([out,retval] AddressBooks** val); [ propget, helpstring("The file name with path for this AddressBook") ] HRESULT FullName([out,retval] BSTR* val); [ propget, helpstring("The file name (without path) for this AddressBook") ] HRESULT Name([out,retval] BSTR* val); [ propget, helpstring("The path (without file name) for this AddressBook") ] HRESULT Path([out,retval] BSTR* val); [ propget, helpstring("Whether the file has been saved since the last changes") ] HRESULT Saved([out,retval] VARIANT_BOOL *val); [ helpstring("close the Address Book") ] HRESULT Close(); [ helpstring("Save changes to Address Book") ] HRESULT Save(); [ propget, helpstring("Returns number of entries.") ] HRESULT Count([out, retval] long* retval); [ propget, restricted, id(DISPID_NEWENUM), helpstring("returns an enumerator for the collection.") ] HRESULT _NewEnum([out, retval] IUnknown** ret); [ helpstring("Add a new Address entry.") ] HRESULT Add([in] BSTR name, [out,retval] Address** ret); [ id(DISPID_VALUE), helpstring("Given a name, returns the Address entry.") ] HRESULT Item([in] BSTR name, [out, retval] Address** ret); [ helpstring("Remove an Address from the collection.") ] HRESULT Remove([in] BSTR name); [ propget, helpstring("returns an enumerator for the collection.") ] HRESULT Enum([out, retval] DIEnum** ret); } Listing Six public void Next(int n, Variant v[], int x[]) { int i; for(i = 0; i < n && enum.hasMoreElements(); ++i) { Variant var = new Variant(enum.nextElement()); v[i] = var; } if(x != null) x[0] = i; if(i < n) /* returns S_FALSE status, indicating end of collection reached */ throw new ComSuccessException(); } Listing Seven // get a COM enumeration object for this collection private AutoEnum getAutoEnum() { /* use an anonymous class to implement the Enumerable * interface required by AutoEnum's constructor */ return new AutoEnum(new Enumerable() { // get an Enumeration on the collection public Enumeration elements() { return entries.elements(); } }); } Listing Eight public void Skip(int n) { while((n-- > 0) && enum.hasMoreElements()) enum.nextElement(); if(n > 0) // returns S_FALSE status, indicating end of collection reached throw new ComSuccessException(); } Listing Nine public IEnumVariant Clone() { throw new ComFailException( StdErrors.E_NOTIMPL, "Clone method not supported"); } Listing Ten enum StdErrors { [helpstring("Unexpected failure")] E_UNEXPECTED = 0x8000FFFF, [helpstring("Not implemented")] E_NOTIMPL = 0x80004001, [helpstring("Ran out of memory")] E_OUTOFMEMORY = 0x8007000E, // etc. }; Listing Eleven enum Errors { E_FIRST = 0x80040200, [helpstring("Index not valid for collection")] E_OUTOFBOUNDS, [helpstring("Specified Item not Found")] E_ITEMNOTFOUND, // etc. }; Listing Twelve public Object NextElement() { if(enum.hasMoreElements()) return enum.nextElement(); else throw new ComFailException( Errors.E_OUTOFBOUNDS, "Attempt to Retrieve after last element"); } Listing Thirteen REM reg.cmd REM Register the Applicationimpl class as a COM object REM /register means register the class REM /class specifies which class REM /clsid specifies the class id, which is the UUID of the coclass REM /progid specifies a human-readable alias for the class id javareg /register /class:Applicationimpl /clsid:"{4f9dfa95-32ef-11d1-b5ac-9e4a44000000}" /progid:"AddressBook.Application" 5