]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/ole/win32/OleAutomation.java
5bf14447eca75f2a550fbc2d8eb985b2103c506d
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / ole / win32 / OleAutomation.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.ole.win32;
15
16
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.internal.*;
19 import org.eclipse.swt.internal.ole.win32.*;
20 import org.eclipse.swt.internal.win32.*;
21
22 /**
23  * OleAutomation provides a generic mechanism for accessing functionality that is
24  * specific to a particular ActiveX Control or OLE Document.
25  *
26  * <p>The OLE Document or ActiveX Control must support the IDispatch interface in order to provide
27  * OleAutomation support. The additional functionality provided by the OLE Object is specified in
28  * its IDL file.  The additional methods can either be to get property values (<code>getProperty</code>),
29  * to set property values (<code>setProperty</code>) or to invoke a method (<code>invoke</code> or
30  * <code>invokeNoReply</code>).  Arguments are passed around in the form of <code>Variant</code>
31  * objects.
32  *
33  * <p>Here is a sample IDL fragment:
34  *
35  * <pre>
36  *      interface IMyControl : IDispatch
37  *      {
38  *              [propget, id(0)] HRESULT maxFileCount([retval, out] int *c);
39  *              [propput, id(0)] HRESULT maxFileCount([in] int c);
40  *              [id(1)] HRESULT AddFile([in] BSTR fileName);
41  *      };
42  * </pre>
43  *
44  * <p>An example of how to interact with this extended functionality is shown below:
45  *
46  * <pre><code>
47  *      OleAutomation automation = new OleAutomation(myControlSite);
48  *
49  *      // Look up the ID of the maxFileCount parameter
50  *      int[] rgdispid = automation.getIDsOfNames(new String[]{"maxFileCount"});
51  *      int maxFileCountID = rgdispid[0];
52  *
53  *      // Set the property maxFileCount to 100:
54  *      if (automation.setProperty(maxFileCountID, new Variant(100))) {
55  *              System.out.println("Max File Count was successfully set.");
56  *      }
57  *
58  *      // Get the new value of the maxFileCount parameter:
59  *      Variant pVarResult = automation.getProperty(maxFileCountID);
60  *      if (pVarResult != null) {
61  *              System.out.println("Max File Count is "+pVarResult.getInt());
62  *      }
63  *
64  *      // Invoke the AddFile method
65  *      // Look up the IDs of the AddFile method and its parameter
66  *      rgdispid = automation.getIDsOfNames(new String[]{"AddFile", "fileName"});
67  *      int dispIdMember = rgdispid[0];
68  *      int[] rgdispidNamedArgs = new int[] {rgdispid[1]};
69  *
70  *      // Convert arguments to Variant objects
71  *      Variant[] rgvarg = new Variant[1];
72  *      String fileName = "C:\\testfile";
73  *      rgvarg[0] = new Variant(fileName);
74  *
75  *      // Call the method
76  *      Variant pVarResult = automation.invoke(dispIdMember, rgvarg, rgdispidNamedArgs);
77  *
78  *      // Check the return value
79  *      if (pVarResult == null || pVarResult.getInt() != OLE.S_OK){
80  *              System.out.println("Failed to add file "+fileName);
81  *      }
82  *
83  *      automation.dispose();
84  *
85  * </code></pre>
86  *
87  * @see <a href="http://www.eclipse.org/swt/snippets/#ole">OLE and ActiveX snippets</a>
88  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: OLEExample, OleWebBrowser</a>
89  */
90 public final class OleAutomation {
91         private IUnknown objIUnknown;
92         private IDispatch objIDispatch;
93         private String exceptionDescription;
94         private ITypeInfo objITypeInfo;
95
96 OleAutomation(IDispatch idispatch) {
97         if (idispatch == null) OLE.error(OLE.ERROR_INVALID_INTERFACE_ADDRESS);
98         objIDispatch = idispatch;
99         objIDispatch.AddRef();
100
101         long[] ppv = new long[1];
102         /* GetTypeInfo([in] iTInfo, [in] lcid, [out] ppTInfo)
103          * AddRef has already been called on ppTInfo by the callee and must be released by the caller.
104          */
105         int result = objIDispatch.GetTypeInfo(0, COM.LOCALE_USER_DEFAULT, ppv);
106         if (result == OLE.S_OK) {
107                 objITypeInfo = new ITypeInfo(ppv[0]);
108         }
109 }
110 /**
111  * Creates an OleAutomation object for the specified client.
112  *
113  * @param clientSite the site for the OLE Document or ActiveX Control whose additional functionality
114  *        you need to access
115  *
116  * @exception IllegalArgumentException <ul>
117  *              <li>ERROR_INVALID_INTERFACE_ADDRESS when called with an invalid client site
118  *      </ul>
119  */
120 public OleAutomation(OleClientSite clientSite) {
121         if (clientSite == null) OLE.error(OLE.ERROR_INVALID_INTERFACE_ADDRESS);
122         objIDispatch = clientSite.getAutomationObject();
123
124         long[] ppv = new long[1];
125         /* GetTypeInfo([in] iTInfo, [in] lcid, [out] ppTInfo)
126          * AddRef has already been called on ppTInfo by the callee and must be released by the caller.
127          */
128         int result = objIDispatch.GetTypeInfo(0, COM.LOCALE_USER_DEFAULT, ppv);
129         if (result == OLE.S_OK) {
130                 objITypeInfo = new ITypeInfo(ppv[0]);
131         }
132 }
133 /**
134  * Creates an OleAutomation object for the specified <code>progID</code>.
135  *
136  * @param progId the unique program identifier of an OLE Document application;
137  *               the value of the ProgID key or the value of the VersionIndependentProgID key specified
138  *               in the registry for the desired OLE Document (for example, the VersionIndependentProgID
139  *               for Word is Word.Document)
140  *
141  * @exception SWTException
142  * <ul><li>ERROR_INVALID_CLASSID when the progId does not map to a registered CLSID
143  *     <li>ERROR_CANNOT_CREATE_OBJECT when failed to create OLE Object
144  *     <li>ERROR_INTERFACE_NOT_FOUND when the OLE object specified does not implement IDispatch
145  * </ul>
146  *
147  * @since 3.6
148  */
149 public OleAutomation(String progId) {
150         try {
151                 OS.OleInitialize(0);
152                 GUID appClsid = getClassID(progId);
153                 if (appClsid == null) {
154                         OS.OleUninitialize();
155                         OLE.error(OLE.ERROR_INVALID_CLASSID);
156                 }
157                 int flags = COM.CLSCTX_INPROC_SERVER | COM.CLSCTX_LOCAL_SERVER;
158                 long[] ppvObject = new long[1];
159                 int result = COM.CoCreateInstance(appClsid, 0, flags, COM.IIDIUnknown, ppvObject);
160                 if (result != COM.S_OK) {
161                         OS.OleUninitialize();
162                         OLE.error(OLE.ERROR_CANNOT_CREATE_OBJECT, result);
163                 }
164                 objIUnknown = new IUnknown(ppvObject[0]);
165
166                 ppvObject[0] = 0;
167                 result = objIUnknown.QueryInterface(COM.IIDIDispatch, ppvObject);
168                 if (result != COM.S_OK) OLE.error(OLE.ERROR_INTERFACE_NOT_FOUND);
169                 objIDispatch = new IDispatch(ppvObject[0]);
170
171                 ppvObject[0] = 0;
172                 result = objIDispatch.GetTypeInfo(0, COM.LOCALE_USER_DEFAULT, ppvObject);
173                 if (result == OLE.S_OK) {
174                         objITypeInfo = new ITypeInfo(ppvObject[0]);
175                 }
176         } catch (SWTException e) {
177                 dispose();
178                 throw e;
179         }
180 }
181 /**
182  * Disposes the automation object.
183  * <p>
184  * This method releases the IDispatch interface on the OLE Document or ActiveX Control.
185  * Do not use the OleAutomation object after it has been disposed.
186  */
187 public void dispose() {
188
189         if (objIDispatch != null){
190                 objIDispatch.Release();
191         }
192         objIDispatch = null;
193
194         if (objITypeInfo != null){
195                 objITypeInfo.Release();
196         }
197         objITypeInfo = null;
198
199         if (objIUnknown != null){
200                 objIUnknown.Release();
201                 OS.OleUninitialize();
202         }
203         objIUnknown = null;
204 }
205 long getAddress() {
206         return objIDispatch.getAddress();
207 }
208 GUID getClassID(String clientName) {
209         // create a GUID struct to hold the result
210         GUID guid = new GUID();
211
212         // create a null terminated array of char
213         char[] buffer = null;
214         if (clientName != null) {
215                 int count = clientName.length();
216                 buffer = new char[count + 1];
217                 clientName.getChars(0, count, buffer, 0);
218         }
219         if (COM.CLSIDFromProgID(buffer, guid) != COM.S_OK){
220                 int result = COM.CLSIDFromString(buffer, guid);
221                 if (result != COM.S_OK) return null;
222         }
223         return guid;
224 }
225 /**
226  * Returns the fully qualified name of the Help file for the given member ID.
227  *
228  * @param dispId the member ID whose Help file is being retrieved.
229  * @return a string representing the fully qualified name of a Help
230  * file or null.
231  */
232 public String getHelpFile(int dispId) {
233         if (objITypeInfo == null) return null;
234         String[] file = new String[1];
235         int rc = objITypeInfo.GetDocumentation(dispId, null, null, null, file );
236         if (rc == OLE.S_OK) return file[0];
237         return null;
238 }
239 /**
240  * Returns the documentation string for the given member ID.
241  *
242  * @param dispId the member ID in which the documentation is being retrieved.
243  * @return the documentation string if it exists; otherwise return null.
244  */
245 public String getDocumentation(int dispId) {
246         if (objITypeInfo == null) return null;
247         String[] doc = new String[1];
248         int rc = objITypeInfo.GetDocumentation(dispId, null, doc, null, null );
249         if (rc == OLE.S_OK) return doc[0];
250         return null;
251 }
252 /**
253  * Returns the property description of a variable at the given index.
254  *
255  * @param index the index of a variable whose property is being retrieved.
256  * @return an OlePropertyDescription for a variable at the given index.
257  */
258 public OlePropertyDescription getPropertyDescription(int index) {
259         if (objITypeInfo == null) return null;
260         long[] ppVarDesc = new long[1];
261         int rc = objITypeInfo.GetVarDesc(index, ppVarDesc);
262         if (rc != OLE.S_OK) return null;
263         VARDESC vardesc = new VARDESC();
264         COM.MoveMemory(vardesc, ppVarDesc[0], VARDESC.sizeof);
265
266         OlePropertyDescription data = new OlePropertyDescription();
267         data.id = vardesc.memid;
268         data.name = getName(vardesc.memid);
269         data.type = vardesc.elemdescVar_tdesc_vt;
270         if (data.type == OLE.VT_PTR) {
271                 short[] vt = new short[1];
272                 OS.MoveMemory(vt, vardesc.elemdescVar_tdesc_union + C.PTR_SIZEOF, 2);
273                 data.type = vt[0];
274         }
275         data.flags = vardesc.wVarFlags;
276         data.kind = vardesc.varkind;
277         data.description = getDocumentation(vardesc.memid);
278         data.helpFile = getHelpFile(vardesc.memid);
279
280         objITypeInfo.ReleaseVarDesc(ppVarDesc[0]);
281         return data;
282 }
283 /**
284  * Returns the description of a function at the given index.
285  *
286  * @param index the index of a function whose property is being retrieved.
287  * @return an OleFunctionDescription for a function at the given index.
288  */
289 public OleFunctionDescription getFunctionDescription(int index) {
290         if (objITypeInfo == null) return null;
291         long[] ppFuncDesc = new long[1];
292         int rc = objITypeInfo.GetFuncDesc(index, ppFuncDesc);
293         if (rc != OLE.S_OK) return null;
294         FUNCDESC funcdesc = new FUNCDESC();
295         COM.MoveMemory(funcdesc, ppFuncDesc[0], FUNCDESC.sizeof);
296
297         OleFunctionDescription data = new OleFunctionDescription();
298
299         data.id = funcdesc.memid;
300         data.optionalArgCount = funcdesc.cParamsOpt;
301         data.invokeKind = funcdesc.invkind;
302         data.funcKind = funcdesc.funckind;
303         data.flags = funcdesc.wFuncFlags;
304         data.callingConvention = funcdesc.callconv;
305         data.documentation = getDocumentation(funcdesc.memid);
306         data.helpFile = getHelpFile(funcdesc.memid);
307
308         String[] names = getNames(funcdesc.memid, funcdesc.cParams + 1);
309         if (names.length > 0) {
310                 data.name = names[0];
311         }
312         data.args = new OleParameterDescription[funcdesc.cParams];
313         for (int i = 0; i < data.args.length; i++) {
314                 data.args[i] = new OleParameterDescription();
315                 if (names.length > i + 1) {
316                         data.args[i].name = names[i + 1];
317                 }
318                 //TODO 0- use structures
319                 short[] vt = new short[1];
320                 OS.MoveMemory(vt, funcdesc.lprgelemdescParam + i * COM.ELEMDESC_sizeof() + C.PTR_SIZEOF, 2);
321                 if (vt[0] == OLE.VT_PTR) {
322                         long [] pTypedesc = new long [1];
323                         OS.MoveMemory(pTypedesc, funcdesc.lprgelemdescParam + i * COM.ELEMDESC_sizeof(), C.PTR_SIZEOF);
324                         short[] vt2 = new short[1];
325                         OS.MoveMemory(vt2, pTypedesc[0] + C.PTR_SIZEOF, 2);
326                         vt[0] = (short)(vt2[0] | COM.VT_BYREF);
327                 }
328                 data.args[i].type = vt[0];
329                 short[] wParamFlags = new short[1];
330                 OS.MoveMemory(wParamFlags, funcdesc.lprgelemdescParam + i * COM.ELEMDESC_sizeof() + COM.TYPEDESC_sizeof () + C.PTR_SIZEOF, 2);
331                 data.args[i].flags = wParamFlags[0];
332         }
333
334         data.returnType = funcdesc.elemdescFunc_tdesc_vt;
335         if (data.returnType == OLE.VT_PTR) {
336                 short[] vt = new short[1];
337                 OS.MoveMemory(vt, funcdesc.elemdescFunc_tdesc_union + C.PTR_SIZEOF, 2);
338                 data.returnType = vt[0];
339         }
340
341         objITypeInfo.ReleaseFuncDesc(ppFuncDesc[0]);
342         return data;
343 }
344 /**
345  * Returns the type info of the current object referenced by the automation.
346  * The type info contains information about the object such as the function descriptions,
347  * the member descriptions and attributes of the type.
348  *
349  * @return the type info of the receiver
350  */
351 public TYPEATTR getTypeInfoAttributes() {
352         if (objITypeInfo == null) return null;
353         long [] ppTypeAttr = new long [1];
354         int rc = objITypeInfo.GetTypeAttr(ppTypeAttr);
355         if (rc != OLE.S_OK) return null;
356         TYPEATTR typeattr = new TYPEATTR();
357         COM.MoveMemory(typeattr, ppTypeAttr[0], TYPEATTR.sizeof);
358         objITypeInfo.ReleaseTypeAttr(ppTypeAttr[0]);
359         return typeattr;
360 }
361 /**
362  * Returns the name of the given member ID.
363  *
364  * @param dispId the member ID in which the name is being retrieved.
365  * @return the name if it exists; otherwise return null.
366  */
367 public String getName(int dispId) {
368         if (objITypeInfo == null) return null;
369         String[] name = new String[1];
370         int rc = objITypeInfo.GetDocumentation(dispId, name, null, null, null );
371         if (rc == OLE.S_OK) return name[0];
372         return null;
373 }
374 /**
375  * Returns the name of a function and parameter names for the specified function ID.
376  *
377  * @param dispId the function ID in which the name and parameters are being retrieved.
378  * @param maxSize the maximum number of names to retrieve.
379  * @return an array of name containing the function name and the parameter names
380  */
381 public String[] getNames(int dispId, int maxSize) {
382         if (objITypeInfo == null) return new String[0];
383         String[] names = new String[maxSize];
384         int[] count = new int[1];
385         int rc = objITypeInfo.GetNames(dispId, names, maxSize, count);
386         if (rc == OLE.S_OK) {
387                 String[] newNames = new String[count[0]];
388                 System.arraycopy(names, 0, newNames, 0, count[0]);
389                 return newNames;
390         }
391         return new String[0];
392 }
393 /**
394  * Returns the positive integer values (IDs) that are associated with the specified names by the
395  * IDispatch implementor.  If you are trying to get the names of the parameters in a method, the first
396  * String in the names array must be the name of the method followed by the names of the parameters.
397  *
398  * @param names an array of names for which you require the identifiers
399  *
400  * @return positive integer values that are associated with the specified names in the same
401  *         order as the names where provided; or null if the names are unknown
402  */
403 public int[] getIDsOfNames(String[] names) {
404
405         int[] rgdispid = new int[names.length];
406         int result = objIDispatch.GetIDsOfNames(new GUID(), names, names.length, COM.LOCALE_USER_DEFAULT, rgdispid);
407         if (result != COM.S_OK) return null;
408
409         return rgdispid;
410 }
411 /**
412  * Returns a description of the last error encountered.
413  *
414  * @return a description of the last error encountered
415  */
416 public String getLastError() {
417
418         return exceptionDescription;
419
420 }
421 /**
422  * Returns the value of the property specified by the dispIdMember.
423  *
424  * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
425  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
426  *
427  * @return the value of the property specified by the dispIdMember or null
428  */
429 public Variant getProperty(int dispIdMember) {
430         Variant pVarResult = new Variant();
431         int result = invoke(dispIdMember, COM.DISPATCH_PROPERTYGET, null, null, pVarResult);
432         return (result == OLE.S_OK) ? pVarResult : null;
433 }
434 /**
435  * Returns the value of the property specified by the dispIdMember.
436  *
437  * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
438  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
439  *
440  * @param rgvarg an array of arguments for the method.  All arguments are considered to be
441  *        read only unless the Variant is a By Reference Variant type.
442  *
443  * @return the value of the property specified by the dispIdMember or null
444  *
445  * @since 2.0
446  */
447 public Variant getProperty(int dispIdMember, Variant[] rgvarg) {
448         Variant pVarResult = new Variant();
449         int result = invoke(dispIdMember, COM.DISPATCH_PROPERTYGET, rgvarg, null, pVarResult);
450         return (result == OLE.S_OK) ? pVarResult : null;
451
452 }
453 /**
454  * Returns the value of the property specified by the dispIdMember.
455  *
456  * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
457  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
458  *
459  * @param rgvarg an array of arguments for the method.  All arguments are considered to be
460  *        read only unless the Variant is a By Reference Variant type.
461  *
462  * @param rgdispidNamedArgs an array of identifiers for the arguments specified in rgvarg; the
463  *        parameter IDs must be in the same order as their corresponding values;
464  *        all arguments must have an identifier - identifiers can be obtained using
465  *        OleAutomation.getIDsOfNames
466  *
467  * @return the value of the property specified by the dispIdMember or null
468  *
469  * @since 2.0
470  */
471 public Variant getProperty(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs) {
472         Variant pVarResult = new Variant();
473         int result = invoke(dispIdMember, COM.DISPATCH_PROPERTYGET, rgvarg, rgdispidNamedArgs, pVarResult);
474         return (result == OLE.S_OK) ? pVarResult : null;
475 }
476 @Override
477 public boolean equals(Object object) {
478         if (object == this) return true;
479         if (object instanceof OleAutomation) {
480                 if (objIDispatch == null) return false;
481                 OleAutomation oleAutomation = ((OleAutomation) object);
482                 if (oleAutomation.objIDispatch == null) return false;
483                 long address1 = objIDispatch.getAddress();
484                 long address2 = oleAutomation.objIDispatch.getAddress();
485                 return address1 == address2;
486         }
487         return false;
488 }
489 /**
490  * Invokes a method on the OLE Object; the method has no parameters.
491  *
492  * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
493  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
494  *
495  * @return the result of the method or null if the method failed to give result information
496  */
497 public Variant invoke(int dispIdMember) {
498         Variant pVarResult = new Variant();
499         int result = invoke(dispIdMember, COM.DISPATCH_METHOD, null, null, pVarResult);
500         return (result == COM.S_OK) ? pVarResult : null;
501 }
502 /**
503  * Invokes a method on the OLE Object; the method has no optional parameters.
504  *
505  * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
506  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
507  *
508  * @param rgvarg an array of arguments for the method.  All arguments are considered to be
509  *        read only unless the Variant is a By Reference Variant type.
510  *
511  * @return the result of the method or null if the method failed to give result information
512  */
513 public Variant invoke(int dispIdMember, Variant[] rgvarg) {
514         Variant pVarResult = new Variant();
515         int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, null, pVarResult);
516         return (result == COM.S_OK) ? pVarResult : null;
517 }
518 /**
519  * Invokes a method on the OLE Object; the method has optional parameters.  It is not
520  * necessary to specify all the optional parameters, only include the parameters for which
521  * you are providing values.
522  *
523  * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
524  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
525  *
526  * @param rgvarg an array of arguments for the method.  All arguments are considered to be
527  *        read only unless the Variant is a By Reference Variant type.
528  *
529  * @param rgdispidNamedArgs an array of identifiers for the arguments specified in rgvarg; the
530  *        parameter IDs must be in the same order as their corresponding values;
531  *        all arguments must have an identifier - identifiers can be obtained using
532  *        OleAutomation.getIDsOfNames
533  *
534  * @return the result of the method or null if the method failed to give result information
535  */
536 public Variant invoke(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs) {
537         Variant pVarResult = new Variant();
538         int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, rgdispidNamedArgs, pVarResult);
539         return (result == COM.S_OK) ? pVarResult : null;
540 }
541 private int invoke(int dispIdMember, int wFlags, Variant[] rgvarg, int[] rgdispidNamedArgs, Variant pVarResult) {
542
543         // get the IDispatch interface for the control
544         if (objIDispatch == null) return COM.E_FAIL;
545
546         // create a DISPPARAMS structure for the input parameters
547         DISPPARAMS pDispParams = new DISPPARAMS();
548         // store arguments in rgvarg
549         if (rgvarg != null && rgvarg.length > 0) {
550                 pDispParams.cArgs = rgvarg.length;
551                 pDispParams.rgvarg = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, VARIANT.sizeof * rgvarg.length);
552                 int offset = 0;
553                 for (int i = rgvarg.length - 1; i >= 0 ; i--) {
554                         rgvarg[i].getData(pDispParams.rgvarg + offset);
555                         offset += VARIANT.sizeof;
556                 }
557         }
558
559         // if arguments have ids, store the ids in rgdispidNamedArgs
560         if (rgdispidNamedArgs != null && rgdispidNamedArgs.length > 0) {
561                 pDispParams.cNamedArgs = rgdispidNamedArgs.length;
562                 pDispParams.rgdispidNamedArgs = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, 4 * rgdispidNamedArgs.length);
563                 int offset = 0;
564                 for (int i = rgdispidNamedArgs.length; i > 0; i--) {
565                         OS.MoveMemory(pDispParams.rgdispidNamedArgs + offset, new int[] {rgdispidNamedArgs[i-1]}, 4);
566                         offset += 4;
567                 }
568         }
569
570         // invoke the method
571         EXCEPINFO excepInfo = new EXCEPINFO();
572         int[] pArgErr = new int[1];
573         long pVarResultAddress = 0;
574         if (pVarResult != null) pVarResultAddress = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
575         int result = objIDispatch.Invoke(dispIdMember, new GUID(), COM.LOCALE_USER_DEFAULT, wFlags, pDispParams, pVarResultAddress, excepInfo, pArgErr);
576
577         if (pVarResultAddress != 0){
578                 pVarResult.setData(pVarResultAddress);
579                 COM.VariantClear(pVarResultAddress);
580                 OS.GlobalFree(pVarResultAddress);
581         }
582
583         // free the Dispparams resources
584         if (pDispParams.rgdispidNamedArgs != 0){
585                 OS.GlobalFree(pDispParams.rgdispidNamedArgs);
586         }
587         if (pDispParams.rgvarg != 0) {
588                 int offset = 0;
589                 for (int i = 0, length = rgvarg.length; i < length; i++){
590                         COM.VariantClear(pDispParams.rgvarg + offset);
591                         offset += VARIANT.sizeof;
592                 }
593                 OS.GlobalFree(pDispParams.rgvarg);
594         }
595
596         // save error string and cleanup EXCEPINFO
597         manageExcepinfo(result, excepInfo);
598
599         return result;
600 }
601 /**
602  * Invokes a method on the OLE Object; the method has no parameters.  In the early days of OLE,
603  * the IDispatch interface was not well defined and some applications (mainly Word) did not support
604  * a return value.  For these applications, call this method instead of calling
605  * <code>public void invoke(int dispIdMember)</code>.
606  *
607  * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
608  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
609  *
610  * @exception org.eclipse.swt.SWTException <ul>
611  *              <li>ERROR_ACTION_NOT_PERFORMED when method invocation fails
612  *      </ul>
613  */
614 public void invokeNoReply(int dispIdMember) {
615         int result = invoke(dispIdMember, COM.DISPATCH_METHOD, null, null, null);
616         if (result != COM.S_OK)
617                 OLE.error(OLE.ERROR_ACTION_NOT_PERFORMED, result);
618 }
619 /**
620  * Invokes a method on the OLE Object; the method has no optional parameters.  In the early days of OLE,
621  * the IDispatch interface was not well defined and some applications (mainly Word) did not support
622  * a return value.  For these applications, call this method instead of calling
623  * <code>public void invoke(int dispIdMember, Variant[] rgvarg)</code>.
624  *
625  * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
626  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
627  *
628  * @param rgvarg an array of arguments for the method.  All arguments are considered to be
629  *        read only unless the Variant is a By Reference Variant type.
630  *
631  * @exception org.eclipse.swt.SWTException <ul>
632  *              <li>ERROR_ACTION_NOT_PERFORMED when method invocation fails
633  *      </ul>
634  */
635 public void invokeNoReply(int dispIdMember, Variant[] rgvarg) {
636         int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, null, null);
637         if (result != COM.S_OK)
638                 OLE.error(OLE.ERROR_ACTION_NOT_PERFORMED, result);
639 }
640 /**
641  * Invokes a method on the OLE Object; the method has optional parameters.  It is not
642  * necessary to specify all the optional parameters, only include the parameters for which
643  * you are providing values.  In the early days of OLE, the IDispatch interface was not well
644  * defined and some applications (mainly Word) did not support a return value.  For these
645  * applications, call this method instead of calling
646  * <code>public void invoke(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs)</code>.
647  *
648  * @param dispIdMember the ID of the method as specified by the IDL of the ActiveX Control; the
649  *        value for the ID can be obtained using OleAutomation.getIDsOfNames
650  *
651  * @param rgvarg an array of arguments for the method.  All arguments are considered to be
652  *        read only unless the Variant is a By Reference Variant type.
653  *
654  * @param rgdispidNamedArgs an array of identifiers for the arguments specified in rgvarg; the
655  *        parameter IDs must be in the same order as their corresponding values;
656  *        all arguments must have an identifier - identifiers can be obtained using
657  *        OleAutomation.getIDsOfNames
658  *
659  * @exception org.eclipse.swt.SWTException <ul>
660  *              <li>ERROR_ACTION_NOT_PERFORMED when method invocation fails
661  *      </ul>
662  */
663 public void invokeNoReply(int dispIdMember, Variant[] rgvarg, int[] rgdispidNamedArgs) {
664         int result = invoke(dispIdMember, COM.DISPATCH_METHOD, rgvarg, rgdispidNamedArgs, null);
665         if (result != COM.S_OK)
666                 OLE.error(OLE.ERROR_ACTION_NOT_PERFORMED, result);
667 }
668 private void manageExcepinfo(int hResult, EXCEPINFO excepInfo) {
669
670         if (hResult == COM.S_OK){
671                 exceptionDescription = "No Error"; //$NON-NLS-1$
672                 return;
673         }
674
675         // extract exception info
676         if (hResult == COM.DISP_E_EXCEPTION) {
677                 if (excepInfo.bstrDescription != 0){
678                         int size = COM.SysStringByteLen(excepInfo.bstrDescription);
679                         char[] buffer = new char[(size + 1) /2];
680                         OS.MoveMemory(buffer, excepInfo.bstrDescription, size);
681                         exceptionDescription = new String(buffer);
682                 } else {
683                         exceptionDescription = "OLE Automation Error Exception "; //$NON-NLS-1$
684                         if (excepInfo.wCode != 0){
685                                 exceptionDescription += "code = "+excepInfo.wCode; //$NON-NLS-1$
686                         } else if (excepInfo.scode != 0){
687                                 exceptionDescription += "code = "+excepInfo.scode; //$NON-NLS-1$
688                         }
689                 }
690         } else {
691                 exceptionDescription = "OLE Automation Error HResult : " + hResult; //$NON-NLS-1$
692         }
693
694         // cleanup EXCEPINFO struct
695         if (excepInfo.bstrDescription != 0)
696                 COM.SysFreeString(excepInfo.bstrDescription);
697         if (excepInfo.bstrHelpFile != 0)
698                 COM.SysFreeString(excepInfo.bstrHelpFile);
699         if (excepInfo.bstrSource != 0)
700                 COM.SysFreeString(excepInfo.bstrSource);
701 }
702 /**
703  * Sets the property specified by the dispIdMember to a new value.
704  *
705  * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
706  *                     value for the ID can be obtained using OleAutomation.getIDsOfNames
707  * @param rgvarg the new value of the property
708  *
709  * @return true if the operation was successful
710  */
711 public boolean setProperty(int dispIdMember, Variant rgvarg) {
712         Variant[] rgvarg2 = new Variant[] {rgvarg};
713         int[] rgdispidNamedArgs = new int[] {COM.DISPID_PROPERTYPUT};
714         int dwFlags = COM.DISPATCH_PROPERTYPUT;
715         if ((rgvarg.getType() & COM.VT_BYREF) == COM.VT_BYREF)
716                 dwFlags = COM.DISPATCH_PROPERTYPUTREF;
717         Variant pVarResult = new Variant();
718         int result = invoke(dispIdMember, dwFlags, rgvarg2, rgdispidNamedArgs, pVarResult);
719         return (result == COM.S_OK);
720 }
721 /**
722  * Sets the property specified by the dispIdMember to a new value.
723  *
724  * @param dispIdMember the ID of the property as specified by the IDL of the ActiveX Control; the
725  *                     value for the ID can be obtained using OleAutomation.getIDsOfNames
726  * @param rgvarg an array of arguments for the method.  All arguments are considered to be
727  *                     read only unless the Variant is a By Reference Variant type.
728  *
729  * @return true if the operation was successful
730  *
731  * @since 2.0
732  */
733 public boolean setProperty(int dispIdMember, Variant[] rgvarg) {
734         int[] rgdispidNamedArgs = new int[] {COM.DISPID_PROPERTYPUT};
735         int dwFlags = COM.DISPATCH_PROPERTYPUT;
736         for (int i = 0; i < rgvarg.length; i++) {
737                 if ((rgvarg[i].getType() & COM.VT_BYREF) == COM.VT_BYREF)
738                 dwFlags = COM.DISPATCH_PROPERTYPUTREF;
739         }
740         Variant pVarResult = new Variant();
741         int result = invoke(dispIdMember, dwFlags, rgvarg, rgdispidNamedArgs, pVarResult);
742         return (result == COM.S_OK);
743 }
744 }