1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the ActiveQt framework of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
19 ** distribution.
20 ** * Neither the name of The Qt Company Ltd nor the names of its
21 ** contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "qaxscript.h"
42
43 #ifndef QT_NO_WIN_ACTIVEQT
44
45 #if defined(Q_CC_GNU)
46 # define QT_NO_QAXSCRIPT
47 #elif defined(Q_CC_BOR) && __BORLANDC__ < 0x560
48 # define QT_NO_QAXSCRIPT
49 #endif
50
51 #include <qapplication.h>
52 #include <qfile.h>
53 #include <qhash.h>
54 #include <qmetaobject.h>
55 #include <quuid.h>
56 #include <qwidget.h>
57
58 #include <qt_windows.h>
59 #ifndef QT_NO_QAXSCRIPT
60 #include <initguid.h>
61 #include <activscp.h>
62 #endif
63
64 #include "../shared/qaxtypes.h"
65
66 QT_BEGIN_NAMESPACE
67
68 struct QAxEngineDescriptor { QString name, extension, code; };
69 static QList<QAxEngineDescriptor> engines;
70
71 class QAxScriptManagerPrivate
72 {
73 public:
74 QHash<QString, QAxScript*> scriptDict;
75 QHash<QString, QAxBase*> objectDict;
76 };
77
78 /*
79 \class QAxScriptSite
80 \brief The QAxScriptSite class implements a Windows Scripting Host
81 \internal
82
83 The QAxScriptSite is used internally to communicate callbacks from the script
84 engine to the script manager.
85 */
86
87 #ifndef QT_NO_QAXSCRIPT
88
89 class QAxScriptSite : public IActiveScriptSite, public IActiveScriptSiteWindow
90 {
91 public:
92 QAxScriptSite(QAxScript *script);
93
94 ULONG WINAPI AddRef();
95 ULONG WINAPI Release();
96 HRESULT WINAPI QueryInterface(REFIID iid, void **ppvObject);
97
98 HRESULT WINAPI GetLCID(LCID *plcid);
99 HRESULT WINAPI GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti);
100 HRESULT WINAPI GetDocVersionString(BSTR *pbstrVersion);
101
102 HRESULT WINAPI OnScriptTerminate(const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo);
103 HRESULT WINAPI OnStateChange(SCRIPTSTATE ssScriptState);
104 HRESULT WINAPI OnScriptError(IActiveScriptError *pscripterror);
105 HRESULT WINAPI OnEnterScript();
106 HRESULT WINAPI OnLeaveScript();
107
108 HRESULT WINAPI GetWindow(HWND *phwnd);
109 HRESULT WINAPI EnableModeless(BOOL fEnable);
110
111 protected:
112 QWidget *window() const;
113
114 private:
115 QAxScript *script;
116 LONG ref;
117 };
118
119 /*
120 Constructs the site for the \a s.
121 */
QAxScriptSite(QAxScript * s)122 QAxScriptSite::QAxScriptSite(QAxScript *s)
123 : script(s), ref(1)
124 {
125 }
126
127 /*
128 Implements IUnknown::AddRef
129 */
AddRef()130 ULONG WINAPI QAxScriptSite::AddRef()
131 {
132 return InterlockedIncrement(&ref);
133 }
134
135 /*
136 Implements IUnknown::Release
137 */
Release()138 ULONG WINAPI QAxScriptSite::Release()
139 {
140 LONG refCount = InterlockedDecrement(&ref);
141 if (!refCount)
142 delete this;
143
144 return refCount;
145 }
146
147 /*
148 Implements IUnknown::QueryInterface
149 */
QueryInterface(REFIID iid,void ** ppvObject)150 HRESULT WINAPI QAxScriptSite::QueryInterface(REFIID iid, void **ppvObject)
151 {
152 *ppvObject = 0;
153 if (iid == IID_IUnknown)
154 *ppvObject = (IUnknown*)(IActiveScriptSite*)this;
155 else if (iid == IID_IActiveScriptSite)
156 *ppvObject = (IActiveScriptSite*)this;
157 else if (iid == IID_IActiveScriptSiteWindow)
158 *ppvObject = (IActiveScriptSiteWindow*)this;
159 else
160 return E_NOINTERFACE;
161
162 AddRef();
163 return S_OK;
164 }
165
166 /*
167 Implements IActiveScriptSite::GetLCID
168
169 This method is not implemented. Use the system-defined locale.
170 */
GetLCID(LCID *)171 HRESULT WINAPI QAxScriptSite::GetLCID(LCID * /*plcid*/)
172 {
173 return E_NOTIMPL;
174 }
175
176 /*
177 Implements IActiveScriptSite::GetItemInfo
178
179 Tries to find the QAxBase for \a pstrName and returns the
180 relevant interfaces in \a item and \a type as requested through \a mask.
181 */
GetItemInfo(LPCOLESTR pstrName,DWORD mask,IUnknown ** item,ITypeInfo ** type)182 HRESULT WINAPI QAxScriptSite::GetItemInfo(LPCOLESTR pstrName, DWORD mask, IUnknown **item, ITypeInfo **type)
183 {
184 if (item)
185 *item = 0;
186 else if (mask & SCRIPTINFO_IUNKNOWN)
187 return E_POINTER;
188
189 if (type)
190 *type = 0;
191 else if (mask & SCRIPTINFO_ITYPEINFO)
192 return E_POINTER;
193
194 QAxBase *object = script->findObject(QString::fromWCharArray(pstrName));
195 if (!object)
196 return TYPE_E_ELEMENTNOTFOUND;
197
198 if (mask & SCRIPTINFO_IUNKNOWN)
199 object->queryInterface(IID_IUnknown, (void**)item);
200 if (mask & SCRIPTINFO_ITYPEINFO) {
201 IProvideClassInfo *classInfo = 0;
202 object->queryInterface(IID_IProvideClassInfo, (void**)&classInfo);
203 if (classInfo) {
204 classInfo->GetClassInfo(type);
205 classInfo->Release();
206 }
207 }
208 return S_OK;
209 }
210
211 /*
212 Implements IActiveScriptSite::GetDocVersionString
213
214 This method is not implemented. The scripting engine should assume
215 that the script is in sync with the document.
216 */
GetDocVersionString(BSTR *)217 HRESULT WINAPI QAxScriptSite::GetDocVersionString(BSTR * /*version*/)
218 {
219 return E_NOTIMPL;
220 }
221
222 /*
223 Implements IActiveScriptSite::OnScriptTerminate
224
225 This method is usually not called, but if it is it fires
226 QAxScript::finished().
227 */
OnScriptTerminate(const VARIANT * result,const EXCEPINFO * exception)228 HRESULT WINAPI QAxScriptSite::OnScriptTerminate(const VARIANT *result, const EXCEPINFO *exception)
229 {
230 emit script->finished();
231
232 if (result && result->vt != VT_EMPTY)
233 emit script->finished(VARIANTToQVariant(*result, 0));
234 if (exception)
235 emit script->finished(exception->wCode,
236 QString::fromWCharArray(exception->bstrSource),
237 QString::fromWCharArray(exception->bstrDescription),
238 QString::fromWCharArray(exception->bstrHelpFile)
239 );
240 return S_OK;
241 }
242
243 /*
244 Implements IActiveScriptSite::OnEnterScript
245
246 Fires QAxScript::entered() to inform the host that the
247 scripting engine has begun executing the script code.
248 */
OnEnterScript()249 HRESULT WINAPI QAxScriptSite::OnEnterScript()
250 {
251 emit script->entered();
252 return S_OK;
253 }
254
255 /*
256 Implements IActiveScriptSite::OnLeaveScript
257
258 Fires QAxScript::finished() to inform the host that the
259 scripting engine has returned from executing the script code.
260 */
OnLeaveScript()261 HRESULT WINAPI QAxScriptSite::OnLeaveScript()
262 {
263 emit script->finished();
264 return S_OK;
265 }
266
267 /*
268 Implements IActiveScriptSite::OnScriptError
269
270 Fires QAxScript::error() to inform the host that an
271 that an execution error occurred while the engine was running the script.
272 */
OnScriptError(IActiveScriptError * error)273 HRESULT WINAPI QAxScriptSite::OnScriptError(IActiveScriptError *error)
274 {
275 EXCEPINFO exception;
276 memset(&exception, 0, sizeof(exception));
277 DWORD context;
278 ULONG lineNumber;
279 LONG charPos;
280 BSTR bstrLineText;
281 QString lineText;
282
283 error->GetExceptionInfo(&exception);
284 error->GetSourcePosition(&context, &lineNumber, &charPos);
285 HRESULT hres = error->GetSourceLineText(&bstrLineText);
286 if (hres == S_OK) {
287 lineText = QString::fromWCharArray(bstrLineText);
288 SysFreeString(bstrLineText);
289 }
290 SysFreeString(exception.bstrSource);
291 SysFreeString(exception.bstrDescription);
292 SysFreeString(exception.bstrHelpFile);
293
294 emit script->error(exception.wCode, QString::fromWCharArray(exception.bstrDescription), lineNumber, lineText);
295
296 return S_OK;
297 }
298
299 /*
300 Implements IActiveScriptSite::OnStateChange
301
302 Fires QAxScript::stateChanged() to inform the
303 the host that the scripting engine has changed states.
304 */
OnStateChange(SCRIPTSTATE ssScriptState)305 HRESULT WINAPI QAxScriptSite::OnStateChange(SCRIPTSTATE ssScriptState)
306 {
307 emit script->stateChanged(ssScriptState);
308 return S_OK;
309 }
310
311 /*
312 \internal
313 Returns the toplevel widget parent of this script, or
314 the application' active window if there is no widget parent.
315 */
window() const316 QWidget *QAxScriptSite::window() const
317 {
318 QWidget *w = 0;
319 QObject *p = script->parent();
320 while (!w && p) {
321 w = qobject_cast<QWidget*>(p);
322 p = p->parent();
323 }
324
325 if (w)
326 w = w->window();
327 if (!w && qApp)
328 w = qApp->activeWindow();
329
330 return w;
331 }
332
333 /*
334 Implements IActiveScriptSiteWindow::GetWindow
335
336 Retrieves the handle to a window that can act as the owner of a
337 pop-up window that the scripting engine must display.
338 */
GetWindow(HWND * phwnd)339 HRESULT WINAPI QAxScriptSite::GetWindow(HWND *phwnd)
340 {
341 if (!phwnd)
342 return E_POINTER;
343
344 *phwnd = 0;
345 QWidget *w = window();
346 if (!w)
347 return E_FAIL;
348
349 *phwnd = w->winId();
350 return S_OK;
351 }
352
353 /*
354 Implements IActiveScriptSiteWindow::EnableModeless
355
356 Causes the host to enable or disable its main window
357 as well as any modeless dialog boxes.
358 */
EnableModeless(BOOL fEnable)359 HRESULT WINAPI QAxScriptSite::EnableModeless(BOOL fEnable)
360 {
361 QWidget *w = window();
362 if (!w)
363 return E_FAIL;
364
365 EnableWindow(w->winId(), fEnable);
366 return S_OK;
367 }
368
369 #endif //QT_NO_QAXSCRIPT
370
371
372 /*!
373 \class QAxScriptEngine
374 \brief The QAxScriptEngine class provides a wrapper around a script engine.
375 \inmodule QAxContainer
376
377 Every instance of the QAxScriptEngine class represents an interpreter
378 for script code in a particular scripting language. The class is usually
379 not used directly. The QAxScript and QAxScriptManager classes provide
380 convenient functions to handle and call script code.
381
382 Direct access to the script engine is provided through
383 queryInterface().
384
385 \warning This class is not available with the bcc5.5 and MingW
386 compilers.
387
388 \sa QAxScript, QAxScriptManager, QAxBase, {ActiveQt Framework}
389 */
390
391 /*!
392 \enum QAxScriptEngine::State
393
394 The State enumeration defines the different states a script
395 engine can be in.
396
397 \value Uninitialized The script has been created, but not yet initialized
398 \value Initialized The script has been initialized, but is not running
399 \value Started The script can execute code, but does not yet handle events
400 \value Connected The script can execute code and is connected so
401 that it can handle events
402 \value Disconnected The script is loaded, but is not connected to
403 event sources
404 \value Closed The script has been closed.
405 */
406
407 /*!
408 Constructs a QAxScriptEngine object interpreting script code in \a language
409 provided by the code in \a script. This is usually done by the QAxScript
410 class when \link QAxScript::load() loading a script\endlink.
411
412 Instances of QAxScriptEngine should always have both a language and a
413 script.
414 */
QAxScriptEngine(const QString & language,QAxScript * script)415 QAxScriptEngine::QAxScriptEngine(const QString &language, QAxScript *script)
416 : QAxObject(script), script_code(script), engine(0), script_language(language)
417 {
418 #ifdef QT_CHECK_STATE
419 if (language.isEmpty())
420 qWarning("QAxScriptEngine: created without language");
421
422 if (!script_code)
423 qWarning("QAxScriptEngine: created without script");
424 #endif
425 setObjectName(QLatin1String("QAxScriptEngine_") + language);
426 disableClassInfo();
427 disableEventSink();
428 }
429
430 /*!
431 Destroys the QAxScriptEngine object, releasing all allocated
432 resources.
433 */
~QAxScriptEngine()434 QAxScriptEngine::~QAxScriptEngine()
435 {
436 #ifndef QT_NO_QAXSCRIPT
437 if (engine) {
438 engine->SetScriptState(SCRIPTSTATE_DISCONNECTED);
439 engine->Close();
440 engine->Release();
441 }
442 #endif
443 }
444
445 /*!
446 \fn QString QAxScriptEngine::scriptLanguage() const
447 Returns the scripting language, for example "VBScript",
448 or "JScript".
449 */
450
451 /*!
452 \reimp
453 */
initialize(IUnknown ** ptr)454 bool QAxScriptEngine::initialize(IUnknown **ptr)
455 {
456 *ptr = 0;
457
458 #ifndef QT_NO_QAXSCRIPT
459 if (!script_code || script_language.isEmpty())
460 return false;
461
462 CLSID clsid;
463 HRESULT hres = CLSIDFromProgID((wchar_t*)script_language.utf16(), &clsid);
464 if(FAILED(hres))
465 return false;
466
467 CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void**)&engine);
468 if (!engine)
469 return false;
470
471 IActiveScriptParse *parser = 0;
472 engine->QueryInterface(IID_IActiveScriptParse, (void**)&parser);
473 if (!parser) {
474 engine->Release();
475 engine = 0;
476 return false;
477 }
478
479 if (engine->SetScriptSite(script_code->script_site) != S_OK) {
480 engine->Release();
481 engine = 0;
482 return false;
483 }
484 if (parser->InitNew() != S_OK) {
485 parser->Release();
486 engine->Release();
487 engine = 0;
488 return false;
489 }
490
491 BSTR bstrCode = QStringToBSTR(script_code->scriptCode());
492 #ifdef Q_OS_WIN64
493 hres = parser->ParseScriptText(bstrCode, 0, 0, 0, DWORDLONG(this), 0, SCRIPTTEXT_ISVISIBLE, 0, 0);
494 #else
495 hres = parser->ParseScriptText(bstrCode, 0, 0, 0, DWORD(this), 0, SCRIPTTEXT_ISVISIBLE, 0, 0);
496 #endif
497 SysFreeString(bstrCode);
498
499 parser->Release();
500 parser = 0;
501
502 script_code->updateObjects();
503
504 if (engine->SetScriptState(SCRIPTSTATE_CONNECTED) != S_OK) {
505 engine = 0;
506 return false;
507 }
508
509 IDispatch *scriptDispatch = 0;
510 engine->GetScriptDispatch(0, &scriptDispatch);
511 if (scriptDispatch) {
512 scriptDispatch->QueryInterface(IID_IUnknown, (void**)ptr);
513 scriptDispatch->Release();
514 }
515 #endif
516
517 return *ptr != 0;
518 }
519
520 /*!
521 \fn bool QAxScriptEngine::isValid() const
522
523 Returns true if the script engine has been initialized
524 correctly; otherwise returns false.
525 */
526
527 /*!
528 Returns true if the script engine supports introspection;
529 otherwise returns false.
530 */
hasIntrospection() const531 bool QAxScriptEngine::hasIntrospection() const
532 {
533 if (!isValid())
534 return false;
535
536 IDispatch *scriptDispatch = 0;
537 QAxBase::queryInterface(IID_IDispatch, (void**)&scriptDispatch);
538 if (!scriptDispatch)
539 return false;
540
541 UINT tic = 0;
542 HRESULT hres = scriptDispatch->GetTypeInfoCount(&tic);
543 scriptDispatch->Release();
544 return hres == S_OK && tic > 0;
545 }
546
547 /*!
548 Requests the interface \a uuid from the script engine object and
549 sets the value of \a iface to the provided interface, or to 0 if
550 the requested interface could not be provided.
551
552 Returns the result of the QueryInterface implementation of the COM
553 object.
554 */
queryInterface(const QUuid & uuid,void ** iface) const555 long QAxScriptEngine::queryInterface(const QUuid &uuid, void **iface) const
556 {
557 *iface = 0;
558 if (!engine)
559 return E_NOTIMPL;
560
561 #ifndef QT_NO_QAXSCRIPT
562 return engine->QueryInterface(uuid, iface);
563 #else
564 Q_UNUSED(uuid)
565 return E_NOTIMPL;
566 #endif
567 }
568
569 /*!
570 Returns the state of the script engine.
571 */
state() const572 QAxScriptEngine::State QAxScriptEngine::state() const
573 {
574 if (!engine)
575 return Uninitialized;
576
577 #ifndef QT_NO_QAXSCRIPT
578 SCRIPTSTATE state;
579 engine->GetScriptState(&state);
580 return (State)state;
581 #else
582 return Uninitialized;
583 #endif
584 }
585
586 /*!
587 Sets the state of the script engine to \a st.
588 Calling this function is usually not necessary.
589 */
setState(State st)590 void QAxScriptEngine::setState(State st)
591 {
592 #ifndef QT_NO_QAXSCRIPT
593 if (!engine)
594 return;
595
596 engine->SetScriptState((SCRIPTSTATE)st);
597 #else
598 Q_UNUSED(st)
599 #endif
600 }
601
602 /*!
603 Registers an item with the script engine. Script code can
604 refer to this item using \a name.
605 */
addItem(const QString & name)606 void QAxScriptEngine::addItem(const QString &name)
607 {
608 #ifndef QT_NO_QAXSCRIPT
609 if (!engine)
610 return;
611
612 engine->AddNamedItem((wchar_t*)name.utf16(), SCRIPTITEM_ISSOURCE|SCRIPTITEM_ISVISIBLE);
613 #else
614 Q_UNUSED(name)
615 #endif
616 }
617
618 /*!
619 \class QAxScript
620 \brief The QAxScript class provides a wrapper around script code.
621 \inmodule QAxContainer
622
623 Every instance of the QAxScript class represents a piece of
624 scripting code in a particular scripting language. The code is
625 loaded into the script engine using load(). Functions declared
626 in the code can be called using call().
627
628 The script provides scriptEngine() provides feedback to the
629 application through signals. The most important signal is the
630 error() signal. Direct access to the QAxScriptEngine is provided
631 through the scriptEngine() function.
632
633 \warning This class is not available with the bcc5.5 and MingW
634 compilers.
635
636 \sa QAxScriptEngine, QAxScriptManager, QAxBase, {ActiveQt Framework}
637 */
638
639 /*!
640 \enum QAxScript::FunctionFlags
641
642 This FunctionFlags enum describes formatting for function introspection.
643
644 \value FunctionNames Only function names are returned.
645 \value FunctionSignatures Returns the functions with signatures.
646 */
647
648 /*!
649 Constructs a QAxScript object called \a name and registers
650 it with the QAxScriptManager \a manager. This is usually done by the
651 QAxScriptManager class when \link QAxScriptManager::load() loading a
652 script\endlink.
653
654 A script should always have a name. A manager is necessary to allow
655 the script code to reference objects in the application. The \a manager
656 takes ownership of the object.
657 */
QAxScript(const QString & name,QAxScriptManager * manager)658 QAxScript::QAxScript(const QString &name, QAxScriptManager *manager)
659 : QObject(manager), script_name(name), script_manager(manager),
660 script_engine(0)
661 {
662 if (manager) {
663 manager->d->scriptDict.insert(name, this);
664 connect(this, SIGNAL(error(int,QString,int,QString)),
665 manager, SLOT(scriptError(int,QString,int,QString)));
666 }
667
668 #ifndef QT_NO_QAXSCRIPT
669 script_site = new QAxScriptSite(this);
670 #else
671 script_site = 0;
672 #endif
673 }
674
675 /*!
676 Destroys the object, releasing all allocated resources.
677 */
~QAxScript()678 QAxScript::~QAxScript()
679 {
680 delete script_engine;
681 script_engine = 0;
682
683 #ifndef QT_NO_QAXSCRIPT
684 script_site->Release();
685 #endif
686 }
687
688 /*!
689 Loads the script source \a code written in language \a language
690 into the script engine. Returns true if \a code was successfully
691 entered into the script engine; otherwise returns false.
692
693 If \a language is empty (the default) it will be determined
694 heuristically. If \a code contains the string \c {End Sub} it will
695 be interpreted as VBScript, otherwise as JScript. Additional
696 scripting languages can be registered using
697 QAxScript::registerEngine().
698
699 This function can only be called once for each QAxScript object,
700 which is done automatically when using QAxScriptManager::load().
701 */
load(const QString & code,const QString & language)702 bool QAxScript::load(const QString &code, const QString &language)
703 {
704 if (script_engine || code.isEmpty())
705 return false;
706
707 script_code = code;
708 QString lang = language;
709 if (lang.isEmpty()) {
710 if (code.contains(QLatin1String("End Sub"), Qt::CaseInsensitive))
711 lang = QLatin1String("VBScript");
712
713 QList<QAxEngineDescriptor>::ConstIterator it;
714 for (it = engines.begin(); it != engines.end(); ++it) {
715 QAxEngineDescriptor engine = *it;
716 if (engine.code.isEmpty())
717 continue;
718
719 if (code.contains(engine.code)) {
720 lang = engine.name;
721 break;
722 }
723 }
724 }
725 if (lang.isEmpty())
726 lang = QLatin1String("JScript");
727
728 script_engine = new QAxScriptEngine(lang, this);
729 // trigger call to initialize
730 script_engine->metaObject();
731
732 return script_engine->isValid();
733 }
734
735 /*!
736 Returns a list of all the functions in this script if the respective
737 script engine supports introspection; otherwise returns an empty list.
738 The functions are either provided with full prototypes or only as
739 names, depending on the value of \a flags.
740
741 \sa QAxScriptEngine::hasIntrospection()
742 */
functions(FunctionFlags flags) const743 QStringList QAxScript::functions(FunctionFlags flags) const
744 {
745 QStringList functions;
746
747 const QMetaObject *mo = script_engine->metaObject();
748 for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
749 const QMetaMethod slot(mo->method(i));
750 if (slot.methodType() != QMetaMethod::Slot || slot.access() != QMetaMethod::Public)
751 continue;
752 QString slotname = QString::fromLatin1(slot.signature());
753 if (slotname.contains(QLatin1Char('_')))
754 continue;
755
756 if (flags == FunctionSignatures)
757 functions << slotname;
758 else
759 functions << slotname.left(slotname.indexOf(QLatin1Char('(')));
760 }
761
762 return functions;
763 }
764
765 /*!
766 Calls \a function, passing the parameters \a var1, \a var1,
767 \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8
768 as arguments and returns the value returned by the function, or an
769 invalid QVariant if the function does not return a value or when
770 the function call failed.
771
772 See QAxScriptManager::call() for more information about how to call
773 script functions.
774 */
call(const QString & function,const QVariant & var1,const QVariant & var2,const QVariant & var3,const QVariant & var4,const QVariant & var5,const QVariant & var6,const QVariant & var7,const QVariant & var8)775 QVariant QAxScript::call(const QString &function, const QVariant &var1,
776 const QVariant &var2,
777 const QVariant &var3,
778 const QVariant &var4,
779 const QVariant &var5,
780 const QVariant &var6,
781 const QVariant &var7,
782 const QVariant &var8)
783 {
784 if (!script_engine)
785 return QVariant();
786
787 return script_engine->dynamicCall(function.toLatin1(), var1, var2, var3, var4, var5, var6, var7, var8);
788 }
789
790 /*!
791 \overload
792
793 Calls \a function passing \a arguments as parameters, and returns
794 the result. Returns when the script's execution has finished.
795
796 See QAxScriptManager::call() for more information about how to call
797 script functions.
798 */
call(const QString & function,QList<QVariant> & arguments)799 QVariant QAxScript::call(const QString &function, QList<QVariant> &arguments)
800 {
801 if (!script_engine)
802 return QVariant();
803
804 return script_engine->dynamicCall(function.toLatin1(), arguments);
805 }
806
807 /*! \internal
808 Registers all objects in the manager with the script engine.
809 */
updateObjects()810 void QAxScript::updateObjects()
811 {
812 if (!script_manager)
813 return;
814
815 script_manager->updateScript(this);
816 }
817
818 /*! \internal
819 Returns the object \a name registered with the manager.
820 */
findObject(const QString & name)821 QAxBase *QAxScript::findObject(const QString &name)
822 {
823 if (!script_manager)
824 return 0;
825
826 return script_manager->d->objectDict.value(name);
827 }
828
829 /*! \fn QString QAxScript::scriptName() const
830 Returns the name of the script.
831 */
832
833 /*! \fn QString QAxScript::scriptCode() const
834 Returns the script's code, or the null-string if no
835 code has been loaded yet.
836
837 \sa load()
838 */
839
840 /*! \fn QAxScriptEngine* QAxScript::scriptEngine() const
841 Returns a pointer to the script engine.
842
843 You can use the object returned to connect signals to the
844 script functions, or to access the script engine directly.
845 */
846
847 /*! \fn void QAxScript::entered()
848
849 This signal is emitted when a script engine has started executing code.
850 */
851
852 /*! \fn void QAxScript::finished()
853
854 This signal is emitted when a script engine has finished executing code.
855 */
856
857 /*!
858 \fn void QAxScript::finished(const QVariant &result)
859 \overload
860
861 \a result contains the script's result. This will be an invalid
862 QVariant if the script has no return value.
863 */
864
865 /*! \fn void QAxScript::finished(int code, const QString &source,
866 const QString &description, const QString &help)
867 \overload
868
869 \a code, \a source, \a description and \a help contain exception information
870 when the script terminated.
871 */
872
873 /*! \fn void QAxScript::stateChanged(int state);
874
875 This signal is emitted when a script engine changes state.
876 \a state can be any value in the QAxScriptEngineState enumeration.
877 */
878
879 /*!
880 \fn void QAxScript::error(int code, const QString &description,
881 int sourcePosition, const QString &sourceText)
882
883 This signal is emitted when an execution error occurred while
884 running a script.
885
886 \a code, \a description, \a sourcePosition and \a sourceText
887 contain information about the execution error.
888 */
889
890
891
892 /*!
893 \class QAxScriptManager
894 \brief The QAxScriptManager class provides a bridge between application objects
895 and script code.
896 \inmodule QAxContainer
897
898 The QAxScriptManager acts as a bridge between the COM objects embedded
899 in the Qt application through QAxObject or QAxWidget, and the scripting
900 languages available through the Windows Script technologies, usually JScript
901 and VBScript.
902
903 Create one QAxScriptManager for each separate document in your
904 application, and add the COM objects the scripts need to access
905 using addObject(). Then load() the script sources and invoke the
906 functions using call().
907
908 \warning This class is not available with the bcc5.5 and MingW
909 compilers.
910
911 \sa QAxScript, QAxScriptEngine, QAxBase, {ActiveQt Framework}
912 */
913
914 /*!
915 Creates a QAxScriptManager object. \a parent is passed on to the
916 QObject constructor.
917
918 It is usual to create one QAxScriptManager for each document in an
919 application.
920 */
QAxScriptManager(QObject * parent)921 QAxScriptManager::QAxScriptManager(QObject *parent)
922 : QObject(parent)
923 {
924 d = new QAxScriptManagerPrivate;
925 }
926
927 /*!
928 Destroys the objects, releasing all allocated resources.
929 */
~QAxScriptManager()930 QAxScriptManager::~QAxScriptManager()
931 {
932 delete d;
933 }
934
935 /*!
936 Returns a list with all the functions that are available.
937 Functions provided by script engines that don't support
938 introspection are not included in the list.
939 The functions are either provided with full prototypes or
940 only as names, depending on the value of \a flags.
941 */
functions(QAxScript::FunctionFlags flags) const942 QStringList QAxScriptManager::functions(QAxScript::FunctionFlags flags) const
943 {
944 QStringList functions;
945
946 QHash<QString, QAxScript*>::ConstIterator scriptIt;
947 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
948 QAxScript *script = scriptIt.value();
949 functions += script->functions(flags);
950 }
951
952 return functions;
953 }
954
955 /*!
956 Returns a list with the names of all the scripts.
957 */
scriptNames() const958 QStringList QAxScriptManager::scriptNames() const
959 {
960 QStringList scripts;
961
962 QHash<QString, QAxScript*>::ConstIterator scriptIt;
963 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
964 scripts << scriptIt.key();
965 }
966
967 return scripts;
968 }
969
970 /*!
971 Returns the script called \a name.
972
973 You can use the returned pointer to call functions directly
974 through QAxScript::call(), to access the script engine directly, or
975 to delete and thus unload the script.
976 */
script(const QString & name) const977 QAxScript *QAxScriptManager::script(const QString &name) const
978 {
979 return d->scriptDict.value(name);
980 }
981
982 /*!
983 Adds \a object to the manager. Scripts handled by this manager
984 can access the object in the code using the object's
985 \l{QObject::objectName}{objectName} property.
986
987 You must add all the necessary objects before loading any scripts.
988 */
addObject(QAxBase * object)989 void QAxScriptManager::addObject(QAxBase *object)
990 {
991 QObject *obj = object->qObject();
992 QString name = obj->objectName();
993 if (d->objectDict.contains(name))
994 return;
995
996 d->objectDict.insert(name, object);
997 connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
998 }
999
1000 /*! \fn void QAxScriptManager::addObject(QObject *object)
1001 \overload
1002
1003 Adds a generic COM wrapper for \a object to the manager. \a object
1004 must be exposed as a COM object using the functionality provided
1005 by the QAxServer module. Applications
1006 using this function you must link against the qaxserver library.
1007 */
1008
1009 /*!
1010 Loads the script source \a code using the script engine for \a
1011 language. The script can later be referred to using its \a name
1012 which should not be empty.
1013
1014 The function returns a pointer to the script for the given
1015 \a code if the \a code was loaded successfully; otherwise it
1016 returns 0.
1017
1018 If \a language is empty it will be determined heuristically. If \a
1019 code contains the string "End Sub" it will be interpreted as
1020 VBScript, otherwise as JScript. Additional script engines can be
1021 registered using registerEngine().
1022
1023 You must add all the objects necessary (using addObject()) \e
1024 before loading any scripts. If \a code declares a function that is
1025 already available (no matter in which language) the first function
1026 is overloaded and can no longer be called via call(); but it will
1027 still be available by calling its \link script() script \endlink
1028 directly.
1029
1030 \sa addObject(), scriptNames(), functions()
1031 */
load(const QString & code,const QString & name,const QString & language)1032 QAxScript *QAxScriptManager::load(const QString &code, const QString &name, const QString &language)
1033 {
1034 QAxScript *script = new QAxScript(name, this);
1035 if (script->load(code, language))
1036 return script;
1037
1038 delete script;
1039 return 0;
1040 }
1041
1042 /*!
1043 \overload
1044
1045 Loads the source code from the \a file. The script can later be
1046 referred to using its \a name which should not be empty.
1047
1048 The function returns a pointer to the script engine for the code
1049 in \a file if \a file was loaded successfully; otherwise it
1050 returns 0.
1051
1052 The script engine used is determined from the file's extension. By
1053 default ".js" files are interpreted as JScript files, and ".vbs"
1054 and ".dsm" files are interpreted as VBScript. Additional script
1055 engines can be registered using registerEngine().
1056 */
load(const QString & file,const QString & name)1057 QAxScript *QAxScriptManager::load(const QString &file, const QString &name)
1058 {
1059 QFile f(file);
1060 if (!f.open(QIODevice::ReadOnly))
1061 return 0;
1062 QByteArray data = f.readAll();
1063 QString contents = QString::fromLocal8Bit(data, data.size());
1064 f.close();
1065
1066 if (contents.isEmpty())
1067 return 0;
1068
1069 QString language;
1070 if (file.endsWith(QLatin1String(".js"))) {
1071 language = QLatin1String("JScript");
1072 } else {
1073 QList<QAxEngineDescriptor>::ConstIterator it;
1074 for (it = engines.begin(); it != engines.end(); ++it) {
1075 QAxEngineDescriptor engine = *it;
1076 if (engine.extension.isEmpty())
1077 continue;
1078
1079 if (file.endsWith(engine.extension)) {
1080 language = engine.name;
1081 break;
1082 }
1083 }
1084 }
1085
1086 if (language.isEmpty())
1087 language = QLatin1String("VBScript");
1088
1089 QAxScript *script = new QAxScript(name, this);
1090 if (script->load(contents, language))
1091 return script;
1092
1093 delete script;
1094 return 0;
1095 }
1096
1097 /*!
1098 Calls \a function, passing the parameters \a var1, \a var1,
1099 \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8
1100 as arguments and returns the value returned by the function, or an
1101 invalid QVariant if the function does not return a value or when
1102 the function call failed. The call returns when the script's
1103 execution has finished.
1104
1105 In most script engines the only supported parameter type is "const
1106 QVariant&", for example, to call a JavaScript function
1107 \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 0
1108 use
1109 \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 1
1110 As with \link QAxBase::dynamicCall() dynamicCall \endlink the
1111 parameters can directly be embedded in the function string.
1112 \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 2
1113 However, this is slower.
1114
1115 Functions provided by script engines that don't support
1116 introspection are not available and must be called directly
1117 using QAxScript::call() on the respective \link script()
1118 script \endlink object.
1119
1120 Note that calling this function can be significantely slower than
1121 using call() on the respective QAxScript directly.
1122 */
call(const QString & function,const QVariant & var1,const QVariant & var2,const QVariant & var3,const QVariant & var4,const QVariant & var5,const QVariant & var6,const QVariant & var7,const QVariant & var8)1123 QVariant QAxScriptManager::call(const QString &function, const QVariant &var1,
1124 const QVariant &var2,
1125 const QVariant &var3,
1126 const QVariant &var4,
1127 const QVariant &var5,
1128 const QVariant &var6,
1129 const QVariant &var7,
1130 const QVariant &var8)
1131 {
1132 QAxScript *s = script(function);
1133 if (!s) {
1134 #ifdef QT_CHECK_STATE
1135 qWarning("QAxScriptManager::call: No script provides function %s, or this function\n"
1136 "\tis provided through an engine that does not support introspection", function.latin1());
1137 #endif
1138 return QVariant();
1139 }
1140
1141 return s->call(function, var1, var2, var3, var4, var5, var6, var7, var8);
1142 }
1143
1144 /*! \overload
1145
1146 Calls \a function passing \a arguments as parameters, and returns
1147 the result. Returns when the script's execution has finished.
1148 */
call(const QString & function,QList<QVariant> & arguments)1149 QVariant QAxScriptManager::call(const QString &function, QList<QVariant> &arguments)
1150 {
1151 QAxScript *s = script(function);
1152 if (!s) {
1153 #ifdef QT_CHECK_STATE
1154 qWarning("QAxScriptManager::call: No script provides function %s, or this function\n"
1155 "\tis provided through an engine that does not support introspection", function.latin1());
1156 #endif
1157 return QVariant();
1158 }
1159
1160 QList<QVariant> args(arguments);
1161 return s->call(function, args);
1162 }
1163
1164 /*!
1165 Registers the script engine called \a name and returns true if the
1166 engine was found; otherwise does nothing and returns false.
1167
1168 The script engine will be used when loading files with the given
1169 \a extension, or when loading source code that contains the string
1170 \a code.
1171 */
registerEngine(const QString & name,const QString & extension,const QString & code)1172 bool QAxScriptManager::registerEngine(const QString &name, const QString &extension, const QString &code)
1173 {
1174 if (name.isEmpty())
1175 return false;
1176
1177 CLSID clsid;
1178 HRESULT hres = CLSIDFromProgID((wchar_t*)name.utf16(), &clsid);
1179 if (hres != S_OK)
1180 return false;
1181
1182 QAxEngineDescriptor engine;
1183 engine.name = name;
1184 engine.extension = extension;
1185 engine.code = code;
1186
1187 engines.prepend(engine);
1188 return true;
1189 }
1190
1191 /*!
1192 Returns a file filter listing all the supported script languages.
1193 This filter string is convenient for use with QFileDialog.
1194 */
scriptFileFilter()1195 QString QAxScriptManager::scriptFileFilter()
1196 {
1197 QString allFiles = QLatin1String("Script Files (*.js *.vbs *.dsm");
1198 QString specialFiles = QLatin1String(";;VBScript Files (*.vbs *.dsm)"
1199 ";;JavaScript Files (*.js)");
1200
1201 QList<QAxEngineDescriptor>::ConstIterator it;
1202 for (it = engines.begin(); it != engines.end(); ++it) {
1203 QAxEngineDescriptor engine = *it;
1204 if (engine.extension.isEmpty())
1205 continue;
1206
1207 allFiles += QLatin1String(" *") + engine.extension;
1208 specialFiles += QLatin1String(";;") + engine.name + QLatin1String(" Files (*") + engine.extension + QLatin1Char(')');
1209 }
1210 allFiles += QLatin1Char(')');
1211
1212 return allFiles + specialFiles + QLatin1String(";;All Files (*.*)");
1213 }
1214
1215 /*!
1216 \fn void QAxScriptManager::error(QAxScript *script, int code, const QString &description,
1217 int sourcePosition, const QString &sourceText)
1218
1219 This signal is emitted when an execution error occurred while
1220 running \a script.
1221
1222 \a code, \a description, \a sourcePosition and \a sourceText
1223 contain information about the execution error.
1224
1225 \warning Do not delete \a script in a slot connected to this signal. Use deleteLater()
1226 instead.
1227 */
1228
1229 /*!
1230 \internal
1231
1232 Returns a pointer to the first QAxScript that knows
1233 about \a function, or 0 if this function is unknown.
1234 */
scriptForFunction(const QString & function) const1235 QAxScript *QAxScriptManager::scriptForFunction(const QString &function) const
1236 {
1237 // check full prototypes if included
1238 if (function.contains(QLatin1Char('('))) {
1239 QHash<QString, QAxScript*>::ConstIterator scriptIt;
1240 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
1241 QAxScript *script = scriptIt.value();
1242
1243 if (script->functions(QAxScript::FunctionSignatures).contains(function))
1244 return script;
1245 }
1246 }
1247
1248 QString funcName = function;
1249 funcName = funcName.left(funcName.indexOf(QLatin1Char('(')));
1250 // second try, checking only names, not prototypes
1251 QHash<QString, QAxScript*>::ConstIterator scriptIt;
1252 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
1253 QAxScript *script = scriptIt.value();
1254
1255 if (script->functions(QAxScript::FunctionNames).contains(funcName))
1256 return script;
1257 }
1258
1259 return 0;
1260 }
1261
1262 /*!
1263 \internal
1264 */
updateScript(QAxScript * script)1265 void QAxScriptManager::updateScript(QAxScript *script)
1266 {
1267 QHash<QString, QAxBase*>::ConstIterator objectIt;
1268 for (objectIt = d->objectDict.constBegin(); objectIt != d->objectDict.constEnd(); ++objectIt) {
1269 QString name = objectIt.key();
1270
1271 QAxScriptEngine *engine = script->scriptEngine();
1272 if (engine)
1273 engine->addItem(name);
1274 }
1275 }
1276
1277 /*!
1278 \internal
1279 */
objectDestroyed(QObject * o)1280 void QAxScriptManager::objectDestroyed(QObject *o)
1281 {
1282 d->objectDict.take(o->objectName());
1283 }
1284
1285 /*!
1286 \internal
1287 */
scriptError(int code,const QString & desc,int spos,const QString & stext)1288 void QAxScriptManager::scriptError(int code, const QString &desc, int spos, const QString &stext)
1289 {
1290 QAxScript *source = qobject_cast<QAxScript*>(sender());
1291 emit error(source, code, desc, spos, stext);
1292 }
1293
1294 QT_END_NAMESPACE
1295 #endif // QT_NO_WIN_ACTIVEQT
1296