source: trunk/src/activeqt/container/qaxscript.cpp@ 792

Last change on this file since 792 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 37.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the ActiveQt framework of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:BSD$
10** You may use this file under the terms of the BSD license as follows:
11**
12** "Redistribution and use in source and binary forms, with or without
13** modification, are permitted provided that the following conditions are
14** met:
15** * Redistributions of source code must retain the above copyright
16** notice, this list of conditions and the following disclaimer.
17** * Redistributions in binary form must reproduce the above copyright
18** notice, this list of conditions and the following disclaimer in
19** the documentation and/or other materials provided with the
20** distribution.
21** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22** the names of its contributors may be used to endorse or promote
23** products derived from this software without specific prior written
24** permission.
25**
26** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
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
66QT_BEGIN_NAMESPACE
67
68struct QAxEngineDescriptor { QString name, extension, code; };
69static QList<QAxEngineDescriptor> engines;
70
71class QAxScriptManagerPrivate
72{
73public:
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
89class QAxScriptSite : public IActiveScriptSite, public IActiveScriptSiteWindow
90{
91public:
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
111protected:
112 QWidget *window() const;
113
114private:
115 QAxScript *script;
116 unsigned long ref;
117};
118
119/*
120 Constructs the site for the \a s.
121*/
122QAxScriptSite::QAxScriptSite(QAxScript *s)
123: script(s), ref(1)
124{
125}
126
127/*
128 Implements IUnknown::AddRef
129*/
130ULONG WINAPI QAxScriptSite::AddRef()
131{
132 return ++ref;
133}
134
135/*
136 Implements IUnknown::Release
137*/
138ULONG WINAPI QAxScriptSite::Release()
139{
140 if (!--ref) {
141 delete this;
142 return 0;
143 }
144 return ref;
145}
146
147/*
148 Implements IUnknown::QueryInterface
149*/
150HRESULT 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*/
171HRESULT 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*/
182HRESULT 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*/
217HRESULT 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*/
228HRESULT 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*/
249HRESULT 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*/
261HRESULT 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*/
273HRESULT 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*/
305HRESULT 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*/
316QWidget *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*/
339HRESULT 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*/
359HRESULT 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*/
415QAxScriptEngine::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*/
434QAxScriptEngine::~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*/
454bool 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*/
531bool 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*/
555long 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 return E_NOTIMPL;
565#endif
566}
567
568/*!
569 Returns the state of the script engine.
570*/
571QAxScriptEngine::State QAxScriptEngine::state() const
572{
573 if (!engine)
574 return Uninitialized;
575
576#ifndef QT_NO_QAXSCRIPT
577 SCRIPTSTATE state;
578 engine->GetScriptState(&state);
579 return (State)state;
580#else
581 return Uninitialized;
582#endif
583}
584
585/*!
586 Sets the state of the script engine to \a st.
587 Calling this function is usually not necessary.
588*/
589void QAxScriptEngine::setState(State st)
590{
591#ifndef QT_NO_QAXSCRIPT
592 if (!engine)
593 return;
594
595 engine->SetScriptState((SCRIPTSTATE)st);
596#endif
597}
598
599/*!
600 Registers an item with the script engine. Script code can
601 refer to this item using \a name.
602*/
603void QAxScriptEngine::addItem(const QString &name)
604{
605#ifndef QT_NO_QAXSCRIPT
606 if (!engine)
607 return;
608
609 engine->AddNamedItem((wchar_t*)name.utf16(), SCRIPTITEM_ISSOURCE|SCRIPTITEM_ISVISIBLE);
610#endif
611}
612
613/*!
614 \class QAxScript
615 \brief The QAxScript class provides a wrapper around script code.
616 \inmodule QAxContainer
617
618 Every instance of the QAxScript class represents a piece of
619 scripting code in a particular scripting language. The code is
620 loaded into the script engine using load(). Functions declared
621 in the code can be called using call().
622
623 The script provides scriptEngine() provides feedback to the
624 application through signals. The most important signal is the
625 error() signal. Direct access to the QAxScriptEngine is provided
626 through the scriptEngine() function.
627
628 \warning This class is not available with the bcc5.5 and MingW
629 compilers.
630
631 \sa QAxScriptEngine, QAxScriptManager, QAxBase, {ActiveQt Framework}
632*/
633
634/*!
635 \enum QAxScript::FunctionFlags
636
637 This FunctionFlags enum describes formatting for function introspection.
638
639 \value FunctionNames Only function names are returned.
640 \value FunctionSignatures Returns the functions with signatures.
641*/
642
643/*!
644 Constructs a QAxScript object called \a name and registers
645 it with the QAxScriptManager \a manager. This is usually done by the
646 QAxScriptManager class when \link QAxScriptManager::load() loading a
647 script\endlink.
648
649 A script should always have a name. A manager is necessary to allow
650 the script code to reference objects in the application. The \a manager
651 takes ownership of the object.
652*/
653QAxScript::QAxScript(const QString &name, QAxScriptManager *manager)
654: QObject(manager), script_name(name), script_manager(manager),
655script_engine(0)
656{
657 if (manager) {
658 manager->d->scriptDict.insert(name, this);
659 connect(this, SIGNAL(error(int,QString,int,QString)),
660 manager, SLOT(scriptError(int,QString,int,QString)));
661 }
662
663#ifndef QT_NO_QAXSCRIPT
664 script_site = new QAxScriptSite(this);
665#else
666 script_site = 0;
667#endif
668}
669
670/*!
671 Destroys the object, releasing all allocated resources.
672*/
673QAxScript::~QAxScript()
674{
675 delete script_engine;
676 script_engine = 0;
677
678#ifndef QT_NO_QAXSCRIPT
679 script_site->Release();
680#endif
681}
682
683/*!
684 Loads the script source \a code written in language \a language
685 into the script engine. Returns true if \a code was successfully
686 entered into the script engine; otherwise returns false.
687
688 If \a language is empty (the default) it will be determined
689 heuristically. If \a code contains the string \c {End Sub} it will
690 be interpreted as VBScript, otherwise as JScript. Additional
691 scripting languages can be registered using
692 QAxScript::registerEngine().
693
694 This function can only be called once for each QAxScript object,
695 which is done automatically when using QAxScriptManager::load().
696*/
697bool QAxScript::load(const QString &code, const QString &language)
698{
699 if (script_engine || code.isEmpty())
700 return false;
701
702 script_code = code;
703 QString lang = language;
704 if (lang.isEmpty()) {
705 if (code.contains(QLatin1String("End Sub"), Qt::CaseInsensitive))
706 lang = QLatin1String("VBScript");
707
708 QList<QAxEngineDescriptor>::ConstIterator it;
709 for (it = engines.begin(); it != engines.end(); ++it) {
710 QAxEngineDescriptor engine = *it;
711 if (engine.code.isEmpty())
712 continue;
713
714 if (code.contains(engine.code)) {
715 lang = engine.name;
716 break;
717 }
718 }
719 }
720 if (lang.isEmpty())
721 lang = QLatin1String("JScript");
722
723 script_engine = new QAxScriptEngine(lang, this);
724 // trigger call to initialize
725 script_engine->metaObject();
726
727 return script_engine->isValid();
728}
729
730/*!
731 Returns a list of all the functions in this script if the respective
732 script engine supports introspection; otherwise returns an empty list.
733 The functions are either provided with full prototypes or only as
734 names, depending on the value of \a flags.
735
736 \sa QAxScriptEngine::hasIntrospection()
737*/
738QStringList QAxScript::functions(FunctionFlags flags) const
739{
740 QStringList functions;
741
742 const QMetaObject *mo = script_engine->metaObject();
743 for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
744 const QMetaMethod slot(mo->method(i));
745 if (slot.methodType() != QMetaMethod::Slot || slot.access() != QMetaMethod::Public)
746 continue;
747 QString slotname = QString::fromLatin1(slot.signature());
748 if (slotname.contains(QLatin1Char('_')))
749 continue;
750
751 if (flags == FunctionSignatures)
752 functions << slotname;
753 else
754 functions << slotname.left(slotname.indexOf(QLatin1Char('(')));
755 }
756
757 return functions;
758}
759
760/*!
761 Calls \a function, passing the parameters \a var1, \a var1,
762 \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8
763 as arguments and returns the value returned by the function, or an
764 invalid QVariant if the function does not return a value or when
765 the function call failed.
766
767 See QAxScriptManager::call() for more information about how to call
768 script functions.
769*/
770QVariant QAxScript::call(const QString &function, const QVariant &var1,
771 const QVariant &var2,
772 const QVariant &var3,
773 const QVariant &var4,
774 const QVariant &var5,
775 const QVariant &var6,
776 const QVariant &var7,
777 const QVariant &var8)
778{
779 if (!script_engine)
780 return QVariant();
781
782 return script_engine->dynamicCall(function.toLatin1(), var1, var2, var3, var4, var5, var6, var7, var8);
783}
784
785/*!
786 \overload
787
788 Calls \a function passing \a arguments as parameters, and returns
789 the result. Returns when the script's execution has finished.
790
791 See QAxScriptManager::call() for more information about how to call
792 script functions.
793*/
794QVariant QAxScript::call(const QString &function, QList<QVariant> &arguments)
795{
796 if (!script_engine)
797 return QVariant();
798
799 return script_engine->dynamicCall(function.toLatin1(), arguments);
800}
801
802/*! \internal
803 Registers all objects in the manager with the script engine.
804*/
805void QAxScript::updateObjects()
806{
807 if (!script_manager)
808 return;
809
810 script_manager->updateScript(this);
811}
812
813/*! \internal
814 Returns the object \a name registered with the manager.
815*/
816QAxBase *QAxScript::findObject(const QString &name)
817{
818 if (!script_manager)
819 return 0;
820
821 return script_manager->d->objectDict.value(name);
822}
823
824/*! \fn QString QAxScript::scriptName() const
825 Returns the name of the script.
826*/
827
828/*! \fn QString QAxScript::scriptCode() const
829 Returns the script's code, or the null-string if no
830 code has been loaded yet.
831
832 \sa load()
833*/
834
835/*! \fn QAxScriptEngine* QAxScript::scriptEngine() const
836 Returns a pointer to the script engine.
837
838 You can use the object returned to connect signals to the
839 script functions, or to access the script engine directly.
840*/
841
842/*! \fn void QAxScript::entered()
843
844 This signal is emitted when a script engine has started executing code.
845*/
846
847/*! \fn void QAxScript::finished()
848
849 This signal is emitted when a script engine has finished executing code.
850*/
851
852/*!
853 \fn void QAxScript::finished(const QVariant &result)
854 \overload
855
856 \a result contains the script's result. This will be an invalid
857 QVariant if the script has no return value.
858*/
859
860/*! \fn void QAxScript::finished(int code, const QString &source,
861 const QString &description, const QString &help)
862 \overload
863
864 \a code, \a source, \a description and \a help contain exception information
865 when the script terminated.
866*/
867
868/*! \fn void QAxScript::stateChanged(int state);
869
870 This signal is emitted when a script engine changes state.
871 \a state can be any value in the QAxScriptEngineState enumeration.
872*/
873
874/*!
875 \fn void QAxScript::error(int code, const QString &description,
876 int sourcePosition, const QString &sourceText)
877
878 This signal is emitted when an execution error occurred while
879 running a script.
880
881 \a code, \a description, \a sourcePosition and \a sourceText
882 contain information about the execution error.
883*/
884
885
886
887/*!
888 \class QAxScriptManager
889 \brief The QAxScriptManager class provides a bridge between application objects
890 and script code.
891 \inmodule QAxContainer
892
893 The QAxScriptManager acts as a bridge between the COM objects embedded
894 in the Qt application through QAxObject or QAxWidget, and the scripting
895 languages available through the Windows Script technologies, usually JScript
896 and VBScript.
897
898 Create one QAxScriptManager for each separate document in your
899 application, and add the COM objects the scripts need to access
900 using addObject(). Then load() the script sources and invoke the
901 functions using call().
902
903 \warning This class is not available with the bcc5.5 and MingW
904 compilers.
905
906 \sa QAxScript, QAxScriptEngine, QAxBase, {ActiveQt Framework}
907*/
908
909/*!
910 Creates a QAxScriptManager object. \a parent is passed on to the
911 QObject constructor.
912
913 It is usual to create one QAxScriptManager for each document in an
914 application.
915*/
916QAxScriptManager::QAxScriptManager(QObject *parent)
917: QObject(parent)
918{
919 d = new QAxScriptManagerPrivate;
920}
921
922/*!
923 Destroys the objects, releasing all allocated resources.
924*/
925QAxScriptManager::~QAxScriptManager()
926{
927 delete d;
928}
929
930/*!
931 Returns a list with all the functions that are available.
932 Functions provided by script engines that don't support
933 introspection are not included in the list.
934 The functions are either provided with full prototypes or
935 only as names, depending on the value of \a flags.
936*/
937QStringList QAxScriptManager::functions(QAxScript::FunctionFlags flags) const
938{
939 QStringList functions;
940
941 QHash<QString, QAxScript*>::ConstIterator scriptIt;
942 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
943 QAxScript *script = scriptIt.value();
944 functions += script->functions(flags);
945 }
946
947 return functions;
948}
949
950/*!
951 Returns a list with the names of all the scripts.
952*/
953QStringList QAxScriptManager::scriptNames() const
954{
955 QStringList scripts;
956
957 QHash<QString, QAxScript*>::ConstIterator scriptIt;
958 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
959 scripts << scriptIt.key();
960 }
961
962 return scripts;
963}
964
965/*!
966 Returns the script called \a name.
967
968 You can use the returned pointer to call functions directly
969 through QAxScript::call(), to access the script engine directly, or
970 to delete and thus unload the script.
971*/
972QAxScript *QAxScriptManager::script(const QString &name) const
973{
974 return d->scriptDict.value(name);
975}
976
977/*!
978 Adds \a object to the manager. Scripts handled by this manager
979 can access the object in the code using the object's
980 \l{QObject::objectName}{objectName} property.
981
982 You must add all the necessary objects before loading any scripts.
983*/
984void QAxScriptManager::addObject(QAxBase *object)
985{
986 QObject *obj = object->qObject();
987 QString name = obj->objectName();
988 if (d->objectDict.contains(name))
989 return;
990
991 d->objectDict.insert(name, object);
992 connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
993}
994
995/*! \fn void QAxScriptManager::addObject(QObject *object)
996 \overload
997
998 Adds a generic COM wrapper for \a object to the manager. \a object
999 must be exposed as a COM object using the functionality provided
1000 by the QAxServer module. Applications
1001 using this function you must link against the qaxserver library.
1002*/
1003
1004/*!
1005 Loads the script source \a code using the script engine for \a
1006 language. The script can later be referred to using its \a name
1007 which should not be empty.
1008
1009 The function returns a pointer to the script for the given
1010 \a code if the \a code was loaded successfully; otherwise it
1011 returns 0.
1012
1013 If \a language is empty it will be determined heuristically. If \a
1014 code contains the string "End Sub" it will be interpreted as
1015 VBScript, otherwise as JScript. Additional script engines can be
1016 registered using registerEngine().
1017
1018 You must add all the objects necessary (using addObject()) \e
1019 before loading any scripts. If \a code declares a function that is
1020 already available (no matter in which language) the first function
1021 is overloaded and can no longer be called via call(); but it will
1022 still be available by calling its \link script() script \endlink
1023 directly.
1024
1025 \sa addObject(), scriptNames(), functions()
1026*/
1027QAxScript *QAxScriptManager::load(const QString &code, const QString &name, const QString &language)
1028{
1029 QAxScript *script = new QAxScript(name, this);
1030 if (script->load(code, language))
1031 return script;
1032
1033 delete script;
1034 return 0;
1035}
1036
1037/*!
1038 \overload
1039
1040 Loads the source code from the \a file. The script can later be
1041 referred to using its \a name which should not be empty.
1042
1043 The function returns a pointer to the script engine for the code
1044 in \a file if \a file was loaded successfully; otherwise it
1045 returns 0.
1046
1047 The script engine used is determined from the file's extension. By
1048 default ".js" files are interpreted as JScript files, and ".vbs"
1049 and ".dsm" files are interpreted as VBScript. Additional script
1050 engines can be registered using registerEngine().
1051*/
1052QAxScript *QAxScriptManager::load(const QString &file, const QString &name)
1053{
1054 QFile f(file);
1055 if (!f.open(QIODevice::ReadOnly))
1056 return 0;
1057 QByteArray data = f.readAll();
1058 QString contents = QString::fromLocal8Bit(data, data.size());
1059 f.close();
1060
1061 if (contents.isEmpty())
1062 return 0;
1063
1064 QString language;
1065 if (file.endsWith(QLatin1String(".js"))) {
1066 language = QLatin1String("JScript");
1067 } else {
1068 QList<QAxEngineDescriptor>::ConstIterator it;
1069 for (it = engines.begin(); it != engines.end(); ++it) {
1070 QAxEngineDescriptor engine = *it;
1071 if (engine.extension.isEmpty())
1072 continue;
1073
1074 if (file.endsWith(engine.extension)) {
1075 language = engine.name;
1076 break;
1077 }
1078 }
1079 }
1080
1081 if (language.isEmpty())
1082 language = QLatin1String("VBScript");
1083
1084 QAxScript *script = new QAxScript(name, this);
1085 if (script->load(contents, language))
1086 return script;
1087
1088 delete script;
1089 return 0;
1090}
1091
1092/*!
1093 Calls \a function, passing the parameters \a var1, \a var1,
1094 \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8
1095 as arguments and returns the value returned by the function, or an
1096 invalid QVariant if the function does not return a value or when
1097 the function call failed. The call returns when the script's
1098 execution has finished.
1099
1100 In most script engines the only supported parameter type is "const
1101 QVariant&", for example, to call a JavaScript function
1102 \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 0
1103 use
1104 \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 1
1105 As with \link QAxBase::dynamicCall() dynamicCall \endlink the
1106 parameters can directly be embedded in the function string.
1107 \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 2
1108 However, this is slower.
1109
1110 Functions provided by script engines that don't support
1111 introspection are not available and must be called directly
1112 using QAxScript::call() on the respective \link script()
1113 script \endlink object.
1114
1115 Note that calling this function can be significantely slower than
1116 using call() on the respective QAxScript directly.
1117*/
1118QVariant QAxScriptManager::call(const QString &function, const QVariant &var1,
1119 const QVariant &var2,
1120 const QVariant &var3,
1121 const QVariant &var4,
1122 const QVariant &var5,
1123 const QVariant &var6,
1124 const QVariant &var7,
1125 const QVariant &var8)
1126{
1127 QAxScript *s = script(function);
1128 if (!s) {
1129#ifdef QT_CHECK_STATE
1130 qWarning("QAxScriptManager::call: No script provides function %s, or this function\n"
1131 "\tis provided through an engine that does not support introspection", function.latin1());
1132#endif
1133 return QVariant();
1134 }
1135
1136 return s->call(function, var1, var2, var3, var4, var5, var6, var7, var8);
1137}
1138
1139/*! \overload
1140
1141 Calls \a function passing \a arguments as parameters, and returns
1142 the result. Returns when the script's execution has finished.
1143*/
1144QVariant QAxScriptManager::call(const QString &function, QList<QVariant> &arguments)
1145{
1146 QAxScript *s = script(function);
1147 if (!s) {
1148#ifdef QT_CHECK_STATE
1149 qWarning("QAxScriptManager::call: No script provides function %s, or this function\n"
1150 "\tis provided through an engine that does not support introspection", function.latin1());
1151#endif
1152 return QVariant();
1153 }
1154
1155 QList<QVariant> args(arguments);
1156 return s->call(function, args);
1157}
1158
1159/*!
1160 Registers the script engine called \a name and returns true if the
1161 engine was found; otherwise does nothing and returns false.
1162
1163 The script engine will be used when loading files with the given
1164 \a extension, or when loading source code that contains the string
1165 \a code.
1166*/
1167bool QAxScriptManager::registerEngine(const QString &name, const QString &extension, const QString &code)
1168{
1169 if (name.isEmpty())
1170 return false;
1171
1172 CLSID clsid;
1173 HRESULT hres = CLSIDFromProgID((wchar_t*)name.utf16(), &clsid);
1174 if (hres != S_OK)
1175 return false;
1176
1177 QAxEngineDescriptor engine;
1178 engine.name = name;
1179 engine.extension = extension;
1180 engine.code = code;
1181
1182 engines.prepend(engine);
1183 return true;
1184}
1185
1186/*!
1187 Returns a file filter listing all the supported script languages.
1188 This filter string is convenient for use with QFileDialog.
1189*/
1190QString QAxScriptManager::scriptFileFilter()
1191{
1192 QString allFiles = QLatin1String("Script Files (*.js *.vbs *.dsm");
1193 QString specialFiles = QLatin1String(";;VBScript Files (*.vbs *.dsm)"
1194 ";;JavaScript Files (*.js)");
1195
1196 QList<QAxEngineDescriptor>::ConstIterator it;
1197 for (it = engines.begin(); it != engines.end(); ++it) {
1198 QAxEngineDescriptor engine = *it;
1199 if (engine.extension.isEmpty())
1200 continue;
1201
1202 allFiles += QLatin1String(" *") + engine.extension;
1203 specialFiles += QLatin1String(";;") + engine.name + QLatin1String(" Files (*") + engine.extension + QLatin1Char(')');
1204 }
1205 allFiles += QLatin1Char(')');
1206
1207 return allFiles + specialFiles + QLatin1String(";;All Files (*.*)");
1208}
1209
1210/*!
1211 \fn void QAxScriptManager::error(QAxScript *script, int code, const QString &description,
1212 int sourcePosition, const QString &sourceText)
1213
1214 This signal is emitted when an execution error occurred while
1215 running \a script.
1216
1217 \a code, \a description, \a sourcePosition and \a sourceText
1218 contain information about the execution error.
1219
1220 \warning Do not delete \a script in a slot connected to this signal. Use deleteLater()
1221 instead.
1222*/
1223
1224/*!
1225 \internal
1226
1227 Returns a pointer to the first QAxScript that knows
1228 about \a function, or 0 if this function is unknown.
1229*/
1230QAxScript *QAxScriptManager::scriptForFunction(const QString &function) const
1231{
1232 // check full prototypes if included
1233 if (function.contains(QLatin1Char('('))) {
1234 QHash<QString, QAxScript*>::ConstIterator scriptIt;
1235 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
1236 QAxScript *script = scriptIt.value();
1237
1238 if (script->functions(QAxScript::FunctionSignatures).contains(function))
1239 return script;
1240 }
1241 }
1242
1243 QString funcName = function;
1244 funcName = funcName.left(funcName.indexOf(QLatin1Char('(')));
1245 // second try, checking only names, not prototypes
1246 QHash<QString, QAxScript*>::ConstIterator scriptIt;
1247 for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
1248 QAxScript *script = scriptIt.value();
1249
1250 if (script->functions(QAxScript::FunctionNames).contains(funcName))
1251 return script;
1252 }
1253
1254 return 0;
1255}
1256
1257/*!
1258 \internal
1259*/
1260void QAxScriptManager::updateScript(QAxScript *script)
1261{
1262 QHash<QString, QAxBase*>::ConstIterator objectIt;
1263 for (objectIt = d->objectDict.constBegin(); objectIt != d->objectDict.constEnd(); ++objectIt) {
1264 QString name = objectIt.key();
1265
1266 QAxScriptEngine *engine = script->scriptEngine();
1267 if (engine)
1268 engine->addItem(name);
1269 }
1270}
1271
1272/*!
1273 \internal
1274*/
1275void QAxScriptManager::objectDestroyed(QObject *o)
1276{
1277 d->objectDict.take(o->objectName());
1278}
1279
1280/*!
1281 \internal
1282*/
1283void QAxScriptManager::scriptError(int code, const QString &desc, int spos, const QString &stext)
1284{
1285 QAxScript *source = qobject_cast<QAxScript*>(sender());
1286 emit error(source, code, desc, spos, stext);
1287}
1288
1289QT_END_NAMESPACE
1290#endif // QT_NO_WIN_ACTIVEQT
Note: See TracBrowser for help on using the repository browser.