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