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