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

Last change on this file since 452 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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