]> git.saurik.com Git - wxWidgets.git/blame - src/msw/ole/automtn.cpp
Fix wxMSW compilation in wxUSE_STL==1 case.
[wxWidgets.git] / src / msw / ole / automtn.cpp
CommitLineData
d980b3e1 1/////////////////////////////////////////////////////////////////////////////
11f104e5 2// Name: src/msw/ole/automtn.cpp
d980b3e1
JS
3// Purpose: OLE automation utilities
4// Author: Julian Smart
5// Modified by:
6// Created: 11/6/98
7// RCS-ID: $Id$
8// Copyright: (c) 1998, Julian Smart
65571936 9// Licence: wxWindows licence
d980b3e1
JS
10/////////////////////////////////////////////////////////////////////////////
11
d980b3e1
JS
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#if defined(__BORLANDC__)
7520f3da 16 #pragma hdrstop
d980b3e1
JS
17#endif
18
f6bcfd97 19// With Borland C++, all samples crash if this is compiled in.
ca5c6ac3
VZ
20#if (defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) || defined(__CYGWIN10__)
21 #undef wxUSE_OLE_AUTOMATION
22 #define wxUSE_OLE_AUTOMATION 0
23#endif
24
e4db172a
WS
25#ifndef WX_PRECOMP
26 #include "wx/log.h"
18680f86 27 #include "wx/math.h"
e4db172a
WS
28#endif
29
5283098e 30#define _FORCENAMELESSUNION
4676948b 31#include "wx/msw/private.h"
ed5317e5 32#include "wx/msw/ole/oleutils.h"
42e69d6b 33#include "wx/msw/ole/automtn.h"
4676948b
JS
34
35#ifdef __WXWINCE__
36#include "wx/msw/wince/time.h"
37#else
f6bcfd97 38#include <time.h>
4676948b 39#endif
f6bcfd97 40
7dee726c
RS
41#include <wtypes.h>
42#include <unknwn.h>
4676948b 43
7dee726c
RS
44#include <ole2.h>
45#define _huge
4676948b
JS
46
47#ifndef __WXWINCE__
42e69d6b 48#include <ole2ver.h>
4676948b
JS
49#endif
50
42e69d6b 51#include <oleauto.h>
17b74d79 52
61bfe4b0
JS
53#if wxUSE_DATETIME
54#include "wx/datetime.h"
b0f76951 55#endif // wxUSE_DATETIME
d980b3e1 56
a2fd865b
VS
57#if wxUSE_OLE_AUTOMATION
58
84f4eef8
VZ
59// Report an OLE error to the user via wxLog.
60static void
61ShowException(const wxString& member,
62 HRESULT hr,
63 EXCEPINFO *pexcep,
64 unsigned int uiArgErr);
65
66// wxAutomationObject
d980b3e1
JS
67
68wxAutomationObject::wxAutomationObject(WXIDISPATCH* dispatchPtr)
69{
0a0e6a5b 70 m_dispatchPtr = dispatchPtr;
d980b3e1
JS
71}
72
73wxAutomationObject::~wxAutomationObject()
74{
0a0e6a5b
WS
75 if (m_dispatchPtr)
76 {
77 ((IDispatch*)m_dispatchPtr)->Release();
78 m_dispatchPtr = NULL;
79 }
d980b3e1
JS
80}
81
82#define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i]))
83
84// For Put/Get, no named arguments are allowed.
85bool wxAutomationObject::Invoke(const wxString& member, int action,
86 wxVariant& retValue, int noArgs, wxVariant args[], const wxVariant* ptrArgs[]) const
87{
0a0e6a5b
WS
88 if (!m_dispatchPtr)
89 return false;
90
91 // nonConstMember is necessary because the wxString class doesn't have enough consts...
92 wxString nonConstMember(member);
93
94 int ch = nonConstMember.Find('.');
95 if (ch != -1)
96 {
97 // Use dot notation to get the next object
98 wxString member2(nonConstMember.Left((size_t) ch));
e4db172a 99 wxString rest(nonConstMember.Right(nonConstMember.length() - ch - 1));
0a0e6a5b
WS
100 wxAutomationObject obj;
101 if (!GetObject(obj, member2))
102 return false;
103 return obj.Invoke(rest, action, retValue, noArgs, args, ptrArgs);
104 }
105
106 VARIANTARG vReturn;
1fbfbfb0 107 VariantInit(& vReturn);
0a0e6a5b
WS
108
109 VARIANTARG* vReturnPtr = & vReturn;
110
111 // Find number of names args
112 int namedArgCount = 0;
113 int i;
114 for (i = 0; i < noArgs; i++)
115 if (!INVOKEARG(i).GetName().IsNull())
12335fa6 116 {
0a0e6a5b
WS
117 namedArgCount ++;
118 }
119
120 int namedArgStringCount = namedArgCount + 1;
121 BSTR* argNames = new BSTR[namedArgStringCount];
122 argNames[0] = wxConvertStringToOle(member);
123
124 // Note that arguments are specified in reverse order
125 // (all totally logical; hey, we're dealing with OLE here.)
126
127 int j = 0;
128 for (i = 0; i < namedArgCount; i++)
129 {
130 if (!INVOKEARG(i).GetName().IsNull())
131 {
132 argNames[(namedArgCount-j)] = wxConvertStringToOle(INVOKEARG(i).GetName());
133 j ++;
134 }
135 }
136
137 // + 1 for the member name, + 1 again in case we're a 'put'
138 DISPID* dispIds = new DISPID[namedArgCount + 2];
139
140 HRESULT hr;
141 DISPPARAMS dispparams;
142 unsigned int uiArgErr;
0a0e6a5b
WS
143
144 // Get the IDs for the member and its arguments. GetIDsOfNames expects the
145 // member name as the first name, followed by argument names (if any).
146 hr = ((IDispatch*)m_dispatchPtr)->GetIDsOfNames(IID_NULL, argNames,
147 1 + namedArgCount, LOCALE_SYSTEM_DEFAULT, dispIds);
148 if (FAILED(hr))
149 {
84f4eef8 150 ShowException(member, hr, NULL, 0);
0a0e6a5b
WS
151 delete[] argNames;
152 delete[] dispIds;
153 return false;
154 }
155
156 // if doing a property put(ref), we need to adjust the first argument to have a
157 // named arg of DISPID_PROPERTYPUT.
158 if (action & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
159 {
160 namedArgCount = 1;
161 dispIds[1] = DISPID_PROPERTYPUT;
d3b9f782 162 vReturnPtr = NULL;
0a0e6a5b
WS
163 }
164
165 // Convert the wxVariants to VARIANTARGs
166 VARIANTARG* oleArgs = new VARIANTARG[noArgs];
167 for (i = 0; i < noArgs; i++)
168 {
169 // Again, reverse args
170 if (!wxConvertVariantToOle(INVOKEARG((noArgs-1) - i), oleArgs[i]))
171 {
172 delete[] argNames;
173 delete[] dispIds;
12335fa6 174 delete[] oleArgs;
0a0e6a5b
WS
175 return false;
176 }
177 }
178
179 dispparams.rgdispidNamedArgs = dispIds + 1;
180 dispparams.rgvarg = oleArgs;
181 dispparams.cArgs = noArgs;
182 dispparams.cNamedArgs = namedArgCount;
183
c50ab33d
VZ
184 EXCEPINFO excep;
185 wxZeroMemory(excep);
0a0e6a5b
WS
186
187 hr = ((IDispatch*)m_dispatchPtr)->Invoke(dispIds[0], IID_NULL, LOCALE_SYSTEM_DEFAULT,
5c519b6c 188 (WORD)action, &dispparams, vReturnPtr, &excep, &uiArgErr);
0a0e6a5b
WS
189
190 for (i = 0; i < namedArgStringCount; i++)
191 {
192 SysFreeString(argNames[i]);
193 }
194 delete[] argNames;
195 delete[] dispIds;
196
197 for (i = 0; i < noArgs; i++)
1fbfbfb0 198 VariantClear(& oleArgs[i]) ;
0a0e6a5b
WS
199 delete[] oleArgs;
200
201 if (FAILED(hr))
202 {
203 // display the exception information if appropriate:
84f4eef8 204 ShowException(member, hr, &excep, uiArgErr);
0a0e6a5b
WS
205
206 // free exception structure information
207 SysFreeString(excep.bstrSource);
208 SysFreeString(excep.bstrDescription);
209 SysFreeString(excep.bstrHelpFile);
210
211 if (vReturnPtr)
1fbfbfb0 212 VariantClear(vReturnPtr);
0a0e6a5b
WS
213 return false;
214 }
215 else
216 {
217 if (vReturnPtr)
218 {
219 // Convert result to wxVariant form
220 wxConvertOleToVariant(vReturn, retValue);
221 // Mustn't release the dispatch pointer
222 if (vReturn.vt == VT_DISPATCH)
223 {
d3b9f782 224 vReturn.pdispVal = NULL;
0a0e6a5b 225 }
1fbfbfb0 226 VariantClear(& vReturn);
12335fa6 227 }
0a0e6a5b
WS
228 }
229 return true;
d980b3e1
JS
230}
231
232// Invoke a member function
233wxVariant wxAutomationObject::CallMethod(const wxString& member, int noArgs, wxVariant args[])
234{
0a0e6a5b
WS
235 wxVariant retVariant;
236 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, args))
237 {
238 retVariant.MakeNull();
239 }
240 return retVariant;
d980b3e1
JS
241}
242
24f4ad95
JS
243wxVariant wxAutomationObject::CallMethodArray(const wxString& member, int noArgs, const wxVariant **args)
244{
0a0e6a5b
WS
245 wxVariant retVariant;
246 if (!Invoke(member, DISPATCH_METHOD, retVariant, noArgs, NULL, args))
247 {
248 retVariant.MakeNull();
249 }
250 return retVariant;
24f4ad95
JS
251}
252
d980b3e1 253wxVariant wxAutomationObject::CallMethod(const wxString& member,
0a0e6a5b
WS
254 const wxVariant& arg1, const wxVariant& arg2,
255 const wxVariant& arg3, const wxVariant& arg4,
256 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 257{
0a0e6a5b
WS
258 const wxVariant** args = new const wxVariant*[6];
259 int i = 0;
260 if (!arg1.IsNull())
261 {
262 args[i] = & arg1;
263 i ++;
264 }
265 if (!arg2.IsNull())
266 {
267 args[i] = & arg2;
268 i ++;
269 }
270 if (!arg3.IsNull())
271 {
272 args[i] = & arg3;
273 i ++;
274 }
275 if (!arg4.IsNull())
276 {
277 args[i] = & arg4;
278 i ++;
279 }
280 if (!arg5.IsNull())
281 {
282 args[i] = & arg5;
283 i ++;
284 }
285 if (!arg6.IsNull())
286 {
287 args[i] = & arg6;
288 i ++;
289 }
290 wxVariant retVariant;
291 if (!Invoke(member, DISPATCH_METHOD, retVariant, i, NULL, args))
292 {
293 retVariant.MakeNull();
294 }
295 delete[] args;
296 return retVariant;
d980b3e1
JS
297}
298
299// Get/Set property
24f4ad95
JS
300wxVariant wxAutomationObject::GetPropertyArray(const wxString& property, int noArgs, const wxVariant **args) const
301{
0a0e6a5b
WS
302 wxVariant retVariant;
303 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args))
304 {
305 retVariant.MakeNull();
306 }
307 return retVariant;
24f4ad95 308}
d980b3e1
JS
309wxVariant wxAutomationObject::GetProperty(const wxString& property, int noArgs, wxVariant args[]) const
310{
0a0e6a5b
WS
311 wxVariant retVariant;
312 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args))
313 {
314 retVariant.MakeNull();
315 }
316 return retVariant;
d980b3e1
JS
317}
318
319wxVariant wxAutomationObject::GetProperty(const wxString& property,
0a0e6a5b
WS
320 const wxVariant& arg1, const wxVariant& arg2,
321 const wxVariant& arg3, const wxVariant& arg4,
322 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 323{
0a0e6a5b
WS
324 const wxVariant** args = new const wxVariant*[6];
325 int i = 0;
326 if (!arg1.IsNull())
327 {
328 args[i] = & arg1;
329 i ++;
330 }
331 if (!arg2.IsNull())
332 {
333 args[i] = & arg2;
334 i ++;
335 }
336 if (!arg3.IsNull())
337 {
338 args[i] = & arg3;
339 i ++;
340 }
341 if (!arg4.IsNull())
342 {
343 args[i] = & arg4;
344 i ++;
345 }
346 if (!arg5.IsNull())
347 {
348 args[i] = & arg5;
349 i ++;
350 }
351 if (!arg6.IsNull())
352 {
353 args[i] = & arg6;
354 i ++;
355 }
356 wxVariant retVariant;
357 if (!Invoke(property, DISPATCH_PROPERTYGET, retVariant, i, NULL, args))
358 {
359 retVariant.MakeNull();
360 }
361 delete[] args;
362 return retVariant;
d980b3e1
JS
363}
364
365bool wxAutomationObject::PutProperty(const wxString& property, int noArgs, wxVariant args[])
366{
0a0e6a5b
WS
367 wxVariant retVariant;
368 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, args))
369 {
370 return false;
371 }
372 return true;
d980b3e1
JS
373}
374
24f4ad95
JS
375bool wxAutomationObject::PutPropertyArray(const wxString& property, int noArgs, const wxVariant **args)
376{
0a0e6a5b
WS
377 wxVariant retVariant;
378 if (!Invoke(property, DISPATCH_PROPERTYPUT, retVariant, noArgs, NULL, args))
379 {
380 return false;
381 }
382 return true;
24f4ad95
JS
383}
384
d980b3e1 385bool wxAutomationObject::PutProperty(const wxString& property,
0a0e6a5b
WS
386 const wxVariant& arg1, const wxVariant& arg2,
387 const wxVariant& arg3, const wxVariant& arg4,
388 const wxVariant& arg5, const wxVariant& arg6)
d980b3e1 389{
0a0e6a5b
WS
390 const wxVariant** args = new const wxVariant*[6];
391 int i = 0;
392 if (!arg1.IsNull())
393 {
394 args[i] = & arg1;
395 i ++;
396 }
397 if (!arg2.IsNull())
398 {
399 args[i] = & arg2;
400 i ++;
401 }
402 if (!arg3.IsNull())
403 {
404 args[i] = & arg3;
405 i ++;
406 }
407 if (!arg4.IsNull())
408 {
409 args[i] = & arg4;
410 i ++;
411 }
412 if (!arg5.IsNull())
413 {
414 args[i] = & arg5;
415 i ++;
416 }
417 if (!arg6.IsNull())
418 {
419 args[i] = & arg6;
420 i ++;
421 }
422 wxVariant retVariant;
423 bool ret = Invoke(property, DISPATCH_PROPERTYPUT, retVariant, i, NULL, args);
424 delete[] args;
425 return ret;
d980b3e1
JS
426}
427
428
429// Uses DISPATCH_PROPERTYGET
430// and returns a dispatch pointer. The calling code should call Release
431// on the pointer, though this could be implicit by constructing an wxAutomationObject
432// with it and letting the destructor call Release.
433WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, wxVariant args[]) const
434{
0a0e6a5b
WS
435 wxVariant retVariant;
436 if (Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, args))
437 {
438 if (retVariant.GetType() == wxT("void*"))
439 {
440 return (WXIDISPATCH*) retVariant.GetVoidPtr();
441 }
442 }
443
d3b9f782 444 return NULL;
d980b3e1
JS
445}
446
24f4ad95
JS
447// Uses DISPATCH_PROPERTYGET
448// and returns a dispatch pointer. The calling code should call Release
449// on the pointer, though this could be implicit by constructing an wxAutomationObject
450// with it and letting the destructor call Release.
451WXIDISPATCH* wxAutomationObject::GetDispatchProperty(const wxString& property, int noArgs, const wxVariant **args) const
452{
0a0e6a5b
WS
453 wxVariant retVariant;
454 if (Invoke(property, DISPATCH_PROPERTYGET, retVariant, noArgs, NULL, args))
455 {
456 if (retVariant.GetType() == wxT("void*"))
457 {
458 return (WXIDISPATCH*) retVariant.GetVoidPtr();
459 }
460 }
461
d3b9f782 462 return NULL;
24f4ad95
JS
463}
464
465
d980b3e1
JS
466// A way of initialising another wxAutomationObject with a dispatch object
467bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, wxVariant args[]) const
468{
0a0e6a5b
WS
469 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
470 if (dispatch)
471 {
472 obj.SetDispatchPtr(dispatch);
473 return true;
474 }
475 else
476 return false;
d980b3e1
JS
477}
478
24f4ad95
JS
479// A way of initialising another wxAutomationObject with a dispatch object
480bool wxAutomationObject::GetObject(wxAutomationObject& obj, const wxString& property, int noArgs, const wxVariant **args) const
481{
0a0e6a5b
WS
482 WXIDISPATCH* dispatch = GetDispatchProperty(property, noArgs, args);
483 if (dispatch)
484 {
485 obj.SetDispatchPtr(dispatch);
486 return true;
487 }
488 else
489 return false;
24f4ad95
JS
490}
491
d980b3e1
JS
492// Get a dispatch pointer from the current object associated
493// with a class id
494bool wxAutomationObject::GetInstance(const wxString& classId) const
495{
0a0e6a5b
WS
496 if (m_dispatchPtr)
497 return false;
498
84f4eef8 499 HRESULT hr;
0a0e6a5b
WS
500 CLSID clsId;
501 IUnknown * pUnk = NULL;
502
5149f75b 503 wxBasicString unicodeName(classId);
0a0e6a5b 504
84f4eef8
VZ
505 hr = CLSIDFromProgID((BSTR) unicodeName, &clsId);
506 if (FAILED(hr))
0a0e6a5b 507 {
84f4eef8 508 ShowException(classId, hr, NULL, 0);
0a0e6a5b
WS
509 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
510 return false;
511 }
512
84f4eef8
VZ
513 hr = GetActiveObject(clsId, NULL, &pUnk);
514 if (FAILED(hr))
0a0e6a5b 515 {
84f4eef8 516 ShowException(classId, hr, NULL, 0);
0a0e6a5b
WS
517 wxLogWarning(wxT("Cannot find an active object"));
518 return false;
519 }
520
84f4eef8
VZ
521 hr = pUnk->QueryInterface(IID_IDispatch, (LPVOID*) &m_dispatchPtr);
522 if (FAILED(hr))
0a0e6a5b 523 {
84f4eef8 524 ShowException(classId, hr, NULL, 0);
0a0e6a5b
WS
525 wxLogWarning(wxT("Cannot find IDispatch interface"));
526 return false;
527 }
528
529 return true;
d980b3e1
JS
530}
531
532// Get a dispatch pointer from a new object associated
533// with the given class id
534bool wxAutomationObject::CreateInstance(const wxString& classId) const
535{
0a0e6a5b
WS
536 if (m_dispatchPtr)
537 return false;
538
84f4eef8 539 HRESULT hr;
0a0e6a5b
WS
540 CLSID clsId;
541
5149f75b 542 wxBasicString unicodeName(classId);
0a0e6a5b 543
84f4eef8
VZ
544 hr = CLSIDFromProgID((BSTR) unicodeName, &clsId);
545 if (FAILED(hr))
0a0e6a5b 546 {
84f4eef8 547 ShowException(classId, hr, NULL, 0);
0a0e6a5b
WS
548 wxLogWarning(wxT("Cannot obtain CLSID from ProgID"));
549 return false;
550 }
551
06936905
VZ
552 // get the server IDispatch interface
553 //
554 // NB: using CLSCTX_INPROC_HANDLER results in failure when getting
555 // Automation interface for Microsoft Office applications so don't use
556 // CLSCTX_ALL which includes it
84f4eef8
VZ
557 hr = CoCreateInstance(clsId, NULL, CLSCTX_SERVER, IID_IDispatch,
558 (void**)&m_dispatchPtr);
559 if (FAILED(hr))
0a0e6a5b 560 {
84f4eef8
VZ
561 ShowException(classId, hr, NULL, 0);
562 wxLogWarning(wxT("Could not start an instance of this class."));
0a0e6a5b
WS
563 return false;
564 }
565
566 return true;
d980b3e1
JS
567}
568
84f4eef8
VZ
569static void
570ShowException(const wxString& member,
571 HRESULT hr,
572 EXCEPINFO *pexcep,
573 unsigned int uiArgErr)
d980b3e1 574{
84f4eef8 575 wxString message;
0a0e6a5b
WS
576 switch (GetScode(hr))
577 {
578 case DISP_E_UNKNOWNNAME:
84f4eef8 579 message = wxT("Unknown name or named argument.");
0a0e6a5b
WS
580 break;
581
582 case DISP_E_BADPARAMCOUNT:
84f4eef8 583 message = wxT("Incorrect number of arguments.");
0a0e6a5b
WS
584 break;
585
586 case DISP_E_EXCEPTION:
84f4eef8
VZ
587 {
588 message = wxT("Error Code (");
589 message << pexcep->wCode ;// unsigned short
590 message += wxT(")");
591 if (pexcep->bstrDescription != NULL)
592 message += pexcep->bstrDescription;
593 else
594 message += wxT("<<No Description>>");
595 }
0a0e6a5b
WS
596 break;
597
598 case DISP_E_MEMBERNOTFOUND:
84f4eef8 599 message = wxT("Method or property not found.");
0a0e6a5b
WS
600 break;
601
602 case DISP_E_OVERFLOW:
84f4eef8 603 message = wxT("Overflow while coercing argument values.");
0a0e6a5b
WS
604 break;
605
606 case DISP_E_NONAMEDARGS:
84f4eef8 607 message = wxT("Object implementation does not support named arguments.");
0a0e6a5b
WS
608 break;
609
610 case DISP_E_UNKNOWNLCID:
84f4eef8 611 message = wxT("The locale ID is unknown.");
0a0e6a5b
WS
612 break;
613
614 case DISP_E_PARAMNOTOPTIONAL:
84f4eef8 615 message = wxT("Missing a required parameter.");
0a0e6a5b
WS
616 break;
617
618 case DISP_E_PARAMNOTFOUND:
84f4eef8
VZ
619 message = wxT("Argument not found, argument.");
620 message << uiArgErr;
0a0e6a5b
WS
621 break;
622
623 case DISP_E_TYPEMISMATCH:
84f4eef8
VZ
624 message = wxT("Type mismatch, argument.");
625 message << uiArgErr;
626 break;
627
628 case ERROR_FILE_NOT_FOUND:
629 message = wxT("The system cannot find the file specified.");
630 break;
631
632 case REGDB_E_CLASSNOTREG:
633 message = wxT("Class not registered.");
0a0e6a5b
WS
634 break;
635
636 default:
84f4eef8
VZ
637 message = wxT("Unknown error occurred. Return value is ");
638 message << hr;
0a0e6a5b
WS
639 break;
640 }
641
84f4eef8 642 wxLogDebug("OLE Automation error in %s: %s", member, message);
d980b3e1
JS
643}
644
84f4eef8 645#endif // wxUSE_OLE_AUTOMATION