diff options
156 files changed, 33121 insertions, 0 deletions
diff --git a/doc/src/activeqt-container.qdoc b/doc/src/activeqt-container.qdoc new file mode 100644 index 0000000..862408b --- /dev/null +++ b/doc/src/activeqt-container.qdoc @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page activeqt-container.html + \title Using ActiveX controls and COM in Qt + \ingroup qt-activex + + \brief A Windows-only extension for accessing ActiveX controls and + COM objects. + + The QAxContainer module is part of the \l ActiveQt framework. It + provides a library implementing a QWidget subclass, QAxWidget, + that acts as a container for ActiveX controls, and a QObject + subclass, QAxObject, that can be used to easily access non-visual + COM objects. Scripting COM objects embedded using these classes + is possible through the QAxScript, QAxScriptManager and + QAxScriptEngine classes, and a set of \l{Tools for ActiveQt}{tools} + makes it easy to access COM objects programmatically. + + The module consists of six classes + \list 1 + \o QAxBase is an abstract class that provides an API to initialize + and access a COM object or ActiveX control. + \o QAxObject provides a QObject that wraps a COM object. + \o QAxWidget is a QWidget that wraps an ActiveX control. + \o QAxScriptManager, QAxScript and QAxScriptEngine provide an + interface to the Windows Script Host. + \endlist + + Some \l{ActiveQt Examples}{example applications} that use + standard ActiveX controls to provide high-level user interface + functionality are provided. + + \sa {ActiveQt Framework} + + Topics: + + \tableofcontents + + \section1 Using the Library + + To build Qt applications that can host COM objects and ActiveX controls + link the application against the QAxContainer module by adding + + \snippet doc/src/snippets/code/doc_src_qaxcontainer.pro 0 + + to your application's \c .pro file. + + \section2 Distributing QAxContainer Applications + + The QAxContainer library is static, so there is no need to redistribute + any additional files when using this module. Note however that the + ActiveX server binaries you are using might not be installed on the + target system, so you have to ship them with your package and register + them during the installation process of your application. + + \section1 Instantiating COM Objects + + To instantiate a COM object use the QAxBase::setControl() API, or pass + the name of the object directly into the constructor of the QAxBase + subclass you are using. + + The control can be specified in a variety of formats, but the fastest + and most powerful format is to use the class ID (CLSID) of the object + directly. The class ID can be prepended with information about a remote + machine that the object should run on, and can include a license key + for licensed controls. + + \section2 Typical Error Messages + + ActiveQt prints error messages to the debug output when it + encounters error situations at runtime. Usually you must run + your program in the debugger to see these messages (e.g. in Visual + Studio's Debug output). + + \section3 Requested control could not be instantiated + + The control requested in QAxBase::setControl() is not installed + on this system, or is not accessible for the current user. + + The control might require administrator rights, or a license key. + If the control is licensed, pass the license key to QAxBase::setControl + as documented. + + \section1 Accessing the Object API + + ActiveQt provides a Qt API to the COM object, and replaces COM + datatypes with Qt equivalents. + + There are four ways to call APIs on the COM object: + + \list + \o Generating a C++ namespace + \o Call-by-name + \o Through a script engine + \o Using the native COM interfaces + \endlist + + \section2 Generating a C++ Namespace + + To generate a C++ namespace for the type library you want to access, + use the \l dumpcpp tool. Run this tool manually on the type library you + want to use, or integrate it into the build system by adding the type + libraries to the \c TYPELIBS variable in your application's \c .pro file: + + \snippet doc/src/snippets/code/doc_src_qaxcontainer.pro 1 + + Note that \l dumpcpp might not be able to expose all APIs in the type + library. + + Include the resulting header file in your code to access the + object APIs through the generated C++ classes. See the + \l{activeqt/qutlook}{Qutlook} example for more information. + + \section2 Call-by-Name + + Use QAxBase::dynamicCall() and QAxBase::querySubObject() as well as + the QObject::setProperty() and QObject::property() APIs to call the + methods and properties of the COM object through their name. Use the + \l dumpdoc tool to get the documentation of the Qt API for any COM + object and its subobjects; note that not all of the COM object's APIs + might be available. + + See the \l{activeqt/webbrowser}{Webbrowser} example for more information. + + \section2 Calling Function Through a Script Engine + + A Qt application can host any ActiveScript engine installed on the system. + The script engine can then run script code that accesses the COM objects. + + To instantiate a script engine, use QAxScriptManager::addObject() to + register the COM objects you want to access from script, and + QAxScriptManager::load() to load the script code into the engine. Then + call the script functions using QAxScriptManager::call() or + QAxScript::call(). + + Which APIs of the COM object are available through scripting depends on + the script language used. + + The \l{testcon - An ActiveX Test Container (ActiveQt)}{ActiveX Test Container} + demonstrates loading of script files. + + \section2 Calling a Function Using the Native COM Interfaces + + To call functions of the COM object that can not be accessed via any + of the above methods it is possible to request the COM interface directly + using QAxBase::queryInterface(). To get a C++ definition of the respective + interface classes use the \c #import directive with the type library + provided with the control; see your compiler manual for details. + + \section2 Typical Error Messages + + ActiveQt prints error messages to the debug output when it + encounters error situations at runtime. Usually you must run + your program in the debugger to see these messages (e.g. in Visual + Studio's Debug output). + + \section3 QAxBase::internalInvoke: No such method + + A QAxBase::dynamicCall() failed - the function prototype did not + match any function available in the object's API. + + \section3 Error calling IDispatch member: Non-optional parameter missing + + A QAxBase::dynamicCall() failed - the function prototype was correct, + but too few parameters were provided. + + \section3 Error calling IDispatch member: Type mismatch in parameter n + + A QAxBase::dynamicCall() failed - the function prototype was correct, + but the paramter at index \c n was of the wrong type and could + not be coerced to the correct type. + + \section3 QAxScriptManager::call(): No script provides this function + + You try to call a function that is provided through an engine + that doesn't provide introspection (ie. ActivePython or + ActivePerl). You need to call the function directly on the + respective QAxScript object. +*/ diff --git a/doc/src/activeqt-server.qdoc b/doc/src/activeqt-server.qdoc new file mode 100644 index 0000000..77cacf8 --- /dev/null +++ b/doc/src/activeqt-server.qdoc @@ -0,0 +1,837 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page activeqt-server.html + \title Building ActiveX servers in Qt + \ingroup qt-activex + + \brief A Windows-only static library for turning a Qt binary into a COM server. + + The QAxServer module is part of the \l ActiveQt framework. It + consists of three classes: + + \list + \o QAxFactory defines a factory for the creation of COM objects. + \o QAxBindable provides an interface between the Qt widget and the + COM object. + \o QAxAggregated can be subclassed to implement additional COM interfaces. + \endlist + + Some \l{ActiveQt Examples}{example implementations} of ActiveX + controls and COM objects are provided. + + \sa {ActiveQt Framework} + + Topics: + + \tableofcontents + + \section1 Using the Library + + To turn a standard Qt application into a COM server using the + QAxServer library you must add \c qaxserver as a CONFIG setting + in your \c .pro file. + + An out-of-process executable server is generated from a \c .pro + file like this: + + \snippet doc/src/snippets/code/doc_src_qaxserver.pro 0 + + To build an in-process server, use a \c .pro file like this: + \snippet doc/src/snippets/code/doc_src_qaxserver.pro 1 + + The files \c qaxserver.rc and \c qaxserver.def are part of the + framework and can be used from their usual location (specify a + path in the \c .pro file), or copied into the project directory. + You can modify these files as long as it includes any file as the + type library entry, ie. you can add version information or specify + a different toolbox icon. + + The \c qaxserver configuration will cause the \c qmake tool to add the + required build steps to the build system: + + \list + \o Link the binary against \c qaxserver.lib instead of \c qtmain.lib + \o Call the \l idc tool to generate an IDL file for the COM server + \o Compile the IDL into a type library using the MIDL tool (part of the + compiler installation) + \o Attach the resulting type library as a binary resource to the server + binary (again using the \l idc tool) + \o Register the server + \endlist + + To skip the post-processing step, also set the \c qaxserver_no_postlink + configuration. + + Additionally you can specify a version number using the \c VERSION + variable, e.g. + + \snippet doc/src/snippets/code/doc_src_qaxserver.pro 2 + + The version number specified will be used as the version of the type + library and of the server when registering. + + \section2 Out-of-Process vs. In-Process + + Whether your COM server should run as a stand-alone executable + or as a shared library in the client process depends mainly on the + type of COM objects you want to provide in the server. + + An executable server has the advantage of being able to run as a + stand-alone application, but adds considerable overhead to the + communication between the COM client and the COM object. If the + control has a programming error only the server process running + the control will crash, and the client application will probably + continue to run. Not all COM clients support executable servers. + + An in-process server is usually smaller and has faster startup + time. The communication between client and server is done directly + through virtual function calls and does not introduce the overhead + required for remote procedure calls. However, if the server crashes the + client application is likely to crash as well, and not every + functionality is available for in-process servers (i.e. register in + the COM's running-object-table). + + Both server types can use Qt either as a shared library, or statically + linked into the server binary. + + \section2 Typical Errors During the Post-Build Steps + + For the ActiveQt specific post-processing steps to work the + server has to meet some requirements: + + \list + \o All controls exposed can be created with nothing but a QApplication + instance being present + \o The initial linking of the server includes a temporary type + library resource + \o All dependencies required to run the server are in the system path + (or in the path used by the calling environment; note that Visual + Studio has its own set of environment variables listed in the + Tools|Options|Directories dialog). + \endlist + + If those requirements are not met one ore more of the following + errors are likely to occur: + + \section3 The Server Executable Crashes + + To generate the IDL the widgets exposed as ActiveX controls need to + be instantiated (the constructor is called). At this point, nothing + else but a QApplication object exists. Your widget constructor must + not rely on any other objects to be created, e.g. it should check for + null-pointers. + + To debug your server run it with -dumpidl outputfile and check where + it crashes. + + Note that no functions of the control are called. + + \section3 The Server Executable Is Not a Valid Win32 Application + + Attaching the type library corrupted the server binary. This is a + bug in Windows and happens only with release builds. + + The first linking step has to link a dummy type library into the + executable that can later be replaced by idc. Add a resource file + with a type library to your project as demonstrated in the examples. + + \section3 "Unable to locate DLL" + + The build system needs to run the server executable to generate + the interface definition, and to register the server. If a dynamic + link library the server links against is not in the path this + might fail (e.g. Visual Studio calls the server using the + enivronment settings specified in the "Directories" option). Make + sure that all DLLs required by your server are located in a + directory that is listed in the path as printed in the error + message box. + + \section3 "Cannot open file ..." + + The ActiveX server could not shut down properly when the last + client stopped using it. It usually takes about two seconds for + the application to terminate, but you might have to use the task + manager to kill the process (e.g. when a client doesn't release + the controls properly). + + \section1 Implementing Controls + + To implement a COM object with Qt, create a subclass of QObject + or any existing QObject subclass. If the class is a subclass of QWidget, + the COM object will be an ActiveX control. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 3 + + The Q_OBJECT macro is required to provide the meta object information + about the widget to the ActiveQt framework. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 4 + + Use the Q_CLASSINFO() macro to specify the COM identifiers for the COM + object. \c ClassID and \c InterfaceID are required, while \c EventsID is + only necessary when your object has signals. To generate these identifiers, + use system tools like \c uuidgen or \c guidgen. + + You can specify additional attributes for each of your classes; see + \l{Class Information and Tuning} for details. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 5 + + Use the Q_PROPERTY() macro to declare properties for the ActiveX control. + + Declare a standard constructor taking a parent object, and functions, + signals and slots like for any QObject subclass. + \footnote + If a standard constructor is not present the compiler will issue + an error "no overloaded function takes 2 parameters" when using + the default factory through the QAXFACTORY_DEFAULT() macro. If you + cannot provide a standard constructor you must implement a + QAxFactory custom factory and call the constructor you have in + your implementation of QAxFactory::create. + \endfootnote + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 6 + + The ActiveQt framework will expose properties and public slots as ActiveX + properties and methods, and signals as ActiveX events, and convert between + the Qt data types and the equivalent COM data types. + + \section2 Data Types + + The Qt data types that are supported for properties are: + + \table + \header + \o Qt data type + \o COM property + \row + \o bool + \o VARIANT_BOOL + \row + \o QString + \o BSTR + \row + \o int + \o int + \row + \o uint + \o unsigned int + \row + \o double + \o double + \row + \o \l qlonglong + \o CY + \row + \o \l qulonglong + \o CY + \row + \o QColor + \o OLE_COLOR + \row + \o QDate + \o DATE + \row + \o QDateTime + \o DATE + \row + \o QTime + \o DATE + \row + \o QFont + \o IFontDisp* + \row + \o QPixmap + \o IPictureDisp* + \footnote + COM cannot marshal IPictureDisp accross process boundaries, + so QPixmap properties cannot be called for out-of-process servers. You + can however marshal the image data via e.g. temporary files. See the + Microsoft + \link http://support.microsoft.com/default.aspx?scid=kb;[LN];Q150034 KB article + Q150034 \endlink for more information. + \endfootnote + \row + \o QVariant + \o VARIANT + \row + \o QVariantList (same as QList\<QVariant\>) + \o SAFEARRAY(VARIANT) + \row + \o QStringList + \o SAFEARRAY(BSTR) + \row + \o QByteArray + \o SAFEARRAY(BYTE) + \row + \o QRect + \o User defined type + \row + \o QSize + \o User defined type + \row + \o QPoint + \o User defined type + \endtable + + The Qt data types that are supported for parameters in signals and + slots are: + \table + \header + \o Qt data type + \o COM parameter + \row + \o bool + \o [in] VARIANT_BOOL + \row + \o bool& + \o [in, out] VARIANT_BOOL* + \row + \o QString, const QString& + \o [in] BSTR + \row + \o QString& + \o [in, out] BSTR* + \row + \o QString& + \o [in, out] BSTR* + \row + \o int + \o [in] int + \row + \o int& + \o [in,out] int + \row + \o uint + \o [in] unsigned int + \row + \o uint& + \o [in, out] unsigned int* + \row + \o double + \o [in] double + \row + \o double& + \o [in, out] double* + \row + \o QColor, const QColor& + \o [in] OLE_COLOR + \row + \o QColor& + \o [in, out] OLE_COLOR* + \row + \o QDate, const QDate& + \o [in] DATE + \row + \o QDate& + \o [in, out] DATE* + \row + \o QDateTime, const QDateTime& + \o [in] DATE + \row + \o QDateTime& + \o [in, out] DATE* + \row + \o QFont, const QFont& + \o [in] IFontDisp* + \row + \o QFont& + \o [in, out] IFontDisp** + \row + \o QPixmap, const QPixmap& + \o [in] IPictureDisp* + \row + \o QPixmap& + \o [in, out] IPictureDisp** + \row + \o QList\<QVariant\>, const QList\<QVariant\>& + \o [in] SAFEARRAY(VARIANT) + \row + \o QList\<QVariant\>& + \o [in, out] SAFEARRAY(VARIANT)* + \row + \o QStringList, const QStringList& + \o [in] SAFEARRAY(BSTR) + \row + \o QStringList& + \o [in, out] SAFEARRAY(BSTR)* + \row + \o QByteArray, const QByteArray& + \o [in] SAFEARRAY(BYTE) + \row + \o QByteArray& + \o [in, out] SAFEARRAY(BYTE)* + \row + \o QObject* + \o [in] IDispatch* + \row + \o QRect& + \footnote + OLE needs to marshal user defined types by reference (ByRef), and cannot + marshal them by value (ByVal). This is why const-references and object + parameters are not supported for QRect, QSize and QPoint. + \endfootnote + \o [in, out] struct QRect (user defined) + \row + \o QSize& + \o [in, out] struct QSize (user defined) + \row + \o QPoint& + \o [in, out] struct QPoint (user defined) + \endtable + + Also supported are exported enums and flags (see Q_ENUMS() and + Q_FLAGS()). The in-parameter types are also supported as + return values. + + Properties and signals/slots that have parameters using any other + data types are ignored by the ActiveQt framework. + + \section2 Sub-Objects + + COM objects can have multiple sub-objects that can represent a sub element + of the COM object. A COM object representing a multi-document spread sheet + application can for example provide one sub-object for each spread sheet. + + Any QObject subclass can be used as the type for a sub object in ActiveX, as + long as it is known to the QAxFactory. Then the type can be used in properties, + or as the return type or paramter of a slot. + + \section2 Property Notification + + To make the properties bindable for the ActiveX client, use multiple + inheritance from the QAxBindable class: + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 7 + + When implementing the property write functions, use the + QAxBindable class's requestPropertyChange() and propertyChanged() + functions to allow ActiveX clients to bind to the control + properties. + \footnote + This is not required, but gives the client more control over + the ActiveX control. + \endfootnote + + \section1 Serving Controls + + To make a COM server available to the COM system it must be registered + in the system registry using five unique identifiers. + These identifiers are provided by tools like \c guidgen or \c uuidgen. + The registration information allows COM to localize the binary providing + a requested ActiveX control, marshall remote procedure calls to the + control and read type information about the methods and properties exposed + by the control. + + To create the COM object when the client asks for it the server must export + an implementation of a QAxFactory. The easist way to do this is to use a set + of macros: + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 8 + + This will export \c MyWidget and \c MyWidget2 as COM objects that can be + created by COM clients, and will register \c MySubType as a type that can + be used in properties and parameters of \c MyWidget and \c MyWidget2. + + The \link QAxFactory QAxFactory class documentation \endlink explains + how to use this macro, and how to implement and use custom factories. + + For out-of-process executable servers you can implement a main() + function to instantiate a QApplication object and enter the event + loop just like any normal Qt application. By default the + application will start as a standard Qt application, but if you + pass \c -activex on the command line it will start as an ActiveX + server. Use QAxFactory::isServer() to create and run a standard + application interface, or to prevent a stand-alone execution: + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 9 + + This is however not necessary as ActiveQt provides a default implementation + of a main function. The default implemenation calls QAxFactory::startServer(), + creates a QApplication instance and calls exec(). + + To build the ActiveX server executable run \c qmake + to generate the makefile, and use your compiler's + make tool as for any other Qt application. The make process will + also register the controls in the system registry by calling the + resulting executable with the \c -regserver command line option. + + If the ActiveX server is an executable, the following command line + options are supported: + \table + \header \o Option \o Result + \row \o \c -regserver \o Registers the server in the system registry + \row \o \c -unregserver \o Unregisters the server from the system registry + \row \o \c -activex \o Starts the application as an ActiveX server + \row \o \c{-dumpidl <file> -version x.y} \o Writes the server's IDL to the + specified file. The type library will have version x.y + \endtable + + In-process servers can be registered using the \c regsvr32 tool available + on all Windows systems. + + \section2 Typical Compile-Time Problems + + The compiler/linker errors listed are based on those issued by the + Microsoft Visual C++ 6.0 compiler. + + \section3 "No overloaded function takes 2 parameters" + + When the error occurs in code that uses the QAXFACTORY_DEFAULT() + macro, the widget class had no constructor that can be used by the + default factory. Either add a standard widget constructor or + implement a custom factory that doesn't require one. + + When the error occurs in code that uses the QAXFACTORY_EXPORT() + macro, the QAxFactory subclass had no appropriate constructor. + Provide a public class constructor like + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 10 + + for your factory class. + + \section3 "Syntax error: bad suffix on number" + + The unique identifiers have not been passed as strings into the + QAXFACTORY_EXPORT() or QAXFACTORY_DEFAULT() macro. + + \section3 "Unresolved external symbol _ucm_instantiate" + + The server does not export an implementation of a QAxFactory. Use + the QAXFACTORY_EXPORT() macro in one of the project's + implementation files to instantiate and export a factory, or use + the QAXFACTORY_DEFAULT() macro to use the default factory. + + \section3 "_ucm_initialize already defined in ..." + + The server exports more than one implementation of a QAxFactory, + or exports the same implementation twice. If you use the default + factory, the QAXFACTORY_DEFAULT() macro must only be used once in + the project. Use a custom QAxFactory implementation and the + QAXFACTORY_EXPORT() macro if the server provides multiple ActiveX + controls. + + \section2 Distributing QAxServer Binaries + + ActiveX servers written with Qt can use Qt either as a shared + library, or have Qt linked statically into the binary. Both ways + will produce rather large packages (either the server binary + itself becomes large, or you have to ship the Qt DLL). + + \section3 Installing Stand-Alone Servers + + When your ActiveX server can also run as a stand-alone application, + run the server executable with the \c -regserver command line + parameter after installing the executable on the target system. + After that the controls provided by the server will be available to + ActiveX clients. + + \section3 Installing In-Process Servers + + When your ActiveX server is part of an installation package, use the + \c regsvr32 tool provided by Microsoft to register the controls on + the target system. If this tool is not present, load the DLL into + your installer process, resolve the \c DllRegisterServer symbol and + call the function: + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 11 + + \section3 Distributing Servers over the Internet + + If you want to use controls in your server in web-pages you need to + make the server available to the browser used to view your page, and + you need to specify the location of the server package in your page. + + To specify the location of a server, use the CODEBASE attribute in + the OBJECT tag of your web-site. The value can point to the server + file itself, to an INF file listing other files the server requires + (e.g. the Qt DLL), or a compressed CAB archive. + + INF and CAB files are documented in almost every book available about + ActiveX and COM programming as well as in the MSDN library and various + other Online resources. The examples include INF files that can be used + to build CAB archives: + + \snippet examples/activeqt/simple/simple.inf 0 + + The CABARC tool from Microsoft can easily generate CAB archives: + + \snippet doc/src/snippets/code/doc_src_qaxserver.qdoc 12 + + The INF files assume a static build of Qt, so no dependencies to other DLLs + are listed in the INF files. To distribute an ActiveX server depending on + DLLs you must add the dependencies, and provide the library files + with the archive. + + \section1 Using the Controls + + To use the ActiveX controls, e.g. to embed them in a web page, use + the \c <object> HTML tag. + + \snippet doc/src/snippets/code/doc_src_qaxserver.qdoc 13 + + To initialize the control's properties, use + + \snippet doc/src/snippets/code/doc_src_qaxserver.qdoc 14 + + If the web browser supports scripting use JavaScript, VBScript + and forms to script the control. The + \l{ActiveQt Examples} include demonstration HTML pages for the example + controls. + + \section2 Supported and Unsupported ActiveX Clients + + The following is largly based on our own experiements with ActiveX + controls and client applications, and is by no means complete. + + \section3 Supported Clients + + These standard applications work with ActiveX controls developed with + ActiveQt. Note that some clients support only in-process controls. + + \list + \o Internet Explorer + \o Microsoft ActiveX Control Test Container + \o Microsoft Visual Studio 6.0 + \o Microsoft Visual Studio.NET/2003 + \o Microsoft Visual Basic 6.0 + \o MFC- and ATL-based containers + \o Sybase PowerBuilder + \o ActiveQt based containers + \endlist + + Microsoft Office applications are supported, but you need to register + the controls as "Insertable" objects. Reimplement QAxFactory::registerClass + to add this attribute to the COM class, or set the "Insertable" class info + for your class to "yes" using the Q_CLASSINFO macro. + + \section3 Unsupported Clients + + We have not managed to make ActiveQt based COM objects work with the + following client applications. + + \list + \o Borland C++ Builder (Versions 5 and 6) + \o Borland Delphi + \endlist + + \section2 Typical Runtime Errors + + \section3 The Server Does Not Respond + + If the system is unable to start the server (check with the task + manager whether the server runs a process), make sure that no DLL + the server depends on is missing from the system path (e.g. the Qt + DLL!). Use a dependency walker to view all dependencies of the server + binary. + + If the server runs (e.g. the task manager lists a process), see + the following section for information on debugging your server. + + \section3 The Object Cannot Be Created + + If the server could be built and registered correctly during the build + process, but the object cannot be initiliazed e.g. by the OLE/COM Object + Viewer application, make sure that no DLL the server depends on is + missing from the system path (e.g. the Qt DLL). Use a dependency walker + to view all dependencies of the server binary. + + If the server runs, see the following section for information on + debugging your server. + + \section2 Debugging Runtime Errors + + To debug an in-process server in Visual Studio, set the server project + as the active project, and specify a client "executable for debug + session" in the project settings (e.g. use the ActiveX Test Container). + You can set breakpoints in your code, and also step into ActiveQt and + Qt code if you installed the debug version. + + To debug an executable server, run the application in a debugger + and start with the command line parameter \c -activex. Then start + your client and create an instance of your ActiveX control. COM + will use the existing process for the next client trying to create + an ActiveX control. + + \section1 Class Information and Tuning + + To provide attributes for each COM class, use the Q_CLASSINFO macro, which is part of + Qt's meta object system. + + \table + \header + \o Key + \o Meaning of value + \row + \o Version + \o The version of the class (1.0 is default) + \row + \o Description + \o A string describing the class. + \row + \o ClassID + \o The class ID. + You must reimplement QAxFactory::classID if not specified. + \row + \o InterfaceID + \o The interface ID. + You must reimplement QAxFactory::interfaceID if not specified. + \row + \o EventsID + \o The event interface ID. + No signals are exposed as COM events if not specified. + \row + \o DefaultProperty + \o The property specified represents the default property of this class. + Ie. the default property of a push button would be "text". + \row + \o DefaultSignal + \o The signal specified respresents the default signal of this class. + Ie. the default signal of a push button would be "clicked". + \row + \o LicenseKey + \o Object creation requires the specified license key. The key can be + empty to require a licensed machine. By default classes are not + licensed. Also see the following section. + \row + \o StockEvents + \o Objects expose stock events if value is "yes". + See \l QAxFactory::hasStockEvents() + \row + \o ToSuperClass + \o Objects expose functionality of all super-classes up to and + including the class name in value. + See \l QAxFactory::exposeToSuperClass() + \row + \o Insertable + \o If the value is "yes" the class is registered to be "Insertable" + and will be listed in OLE 2 containers (ie. Microsoft Office). This + attribute is not be set by default. + \row + \o Aggregatable + \o If the value is "no" the class does not support aggregation. By + default aggregation is supported. + \row + \o Creatable + \o If the value is "no" the class cannot be created by the client, + and is only available through the API of another class (ie. the + class is a sub-type). + \row + \o RegisterObject + \o If the value is "yes" objects of this class are registered with + OLE and accessible from the running object table (ie. clients + can connect to an already running instance of this class). This + attribute is only supported in out-of-process servers. + \row + \o MIME + \o The object can handle data and files of the format specified in the + value. The value has the format mime:extension:description. Multiple + formats are separated by a semicolon. + \row + \o CoClassAlias + \o The classname used in the generated IDL and in the registry. This is + esp. useful for C++ classes that live in a namespace - by default, + ActiveQt just removes the "::" to make the IDL compile. + \endtable + + Note that both keys and values are case sensitive. + + The following declares version 2.0 of a class that exposes only its + own API, and is available in the "Insert Objects" dialog of Microsoft + Office applications. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 15 + + \section2 Developing Licensed Components + + If you develop components you might want to control who is able to instantiate + those components. Since the server binary can be shipped to and registered on + any client machine it is possible for anybody to use those components in his + own software. + + Licensing components can be done using a variety of techniques, e.g. the code + creating the control can provide a license key, or the machine on which the + control is supposed to run needs to be licensed. + + To mark a Qt class as licensed specify a "LicenseKey" using the + Q_CLASSINFO() macro. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 16 + + The key is required to be able to create an instance of \c MyLicensedControl + on a machine that is not licensed itself. The licensed developer can now + redistributes the server binary with his application, which creates the control + using the value of "LicenseKey", while users of the application cannot create + the control without the license key. + + If a single license key for the control is not sufficient (ie. you want + differnet developers to receive different license keys) you can specify an + empty key to indicate that the control requires a license, and reimplement + \l QAxFactory::validateLicenseKey() to verify that a license exists on the + system (ie. through a license file). + + \section2 More Interfaces + + ActiveX controls provided by ActiveQt servers support a minimal set of COM + interfaces to implement the OLE specifications. When the ActiveX class inherits + from the QAxBindable class it can also implement additional COM interfaces. + + Create a new subclass of QAxAggregated and use multiple inheritance + to subclass additional COM interface classes. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 17 + + Reimplement the QAxAggregated::queryInterface() function to + support the additional COM interfaces. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 18 + + Since \c ISomeCOMInterface is a subclass of \c IUnknown you will + have to implement the \c QueryInterface(), \c AddRef(), and \c + Release() functions. Use the QAXAGG_IUNKNOWN macro in your + class definition to do that. If you implement the \c IUnknown + functions manually, delegate the calls to the interface pointer + returned by the QAxAggregated::controllingUnknown() function, + e.g. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 19 + + Do not support the \c IUnknown interface itself in your + \l{QAxAggregated::queryInterface()}{queryInterface()} + implementation. + + Implement the methods of the COM interfaces, and use QAxAggregated::object() + if you need to make calls to the QObject subclass implementing the control. + + In your QAxBindable subclass, implement + QAxBindable::createAggregate() to return a new object of the + QAxAggregated subclass. + + \snippet doc/src/snippets/code/doc_src_qaxserver.cpp 20 +*/ diff --git a/doc/src/activeqt.qdoc b/doc/src/activeqt.qdoc new file mode 100644 index 0000000..ba4a92f --- /dev/null +++ b/doc/src/activeqt.qdoc @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \group activeqt-tools + \title Tools for ActiveQt + \brief Tools to help integrate Qt applications with ActiveX components. + + These tools provide support for integrating Qt with ActiveX components. + + \generatelist{related} + + \sa {ActiveQt Framework} +*/ + +/*! + \page activeqt.html + \title Qt's ActiveX Framework (ActiveQt) + \brief An overview of Qt's ActiveX and COM integration on Windows. + + \ingroup qt-activex + \keyword ActiveQt + \target ActiveQt Framework + + Qt's ActiveX and COM support allows Qt for Windows developers to: + + \list 1 + \o Access and use ActiveX controls and COM objects provided by any + ActiveX server in their Qt applications. + \o Make their Qt applications available as COM servers, with + any number of Qt objects and widgets as COM objects and ActiveX + controls. + \endlist + + For more information about using ActiveX with Qt, see + \l{Building ActiveX servers in Qt}. + + The ActiveQt framework consists of two modules: + + \list + \o The \l{Using ActiveX controls and COM in Qt}{QAxContainer} + module is a static library implementing QObject and QWidget subclasses, + QAxObject and QAxWidget, that act as containers for COM objects and + ActiveX controls. + \o The \l{Building ActiveX servers in Qt}{QAxServer} + module is a static library that implements + functionality for in-process and executable COM servers. This + module provides the QAxAggregated, QAxBindable and QAxFactory + classes. + \endlist + + A set of \l{Tools for ActiveQt}{tools} is provided to simplify the + developing and building of Qt projects that use ActiveX. + + To build the static libraries, change into the \c activeqt directory + (usually \c QTDIR/src/activeqt), and run \c qmake and your make + tool in both the \c container and the \c control subdirectory. + The libraries \c qaxcontainer.lib and \c qaxserver.lib will be linked + into \c QTDIR/lib. + + If you are using a shared configuration of Qt enter the \c plugin + subdirectory and run \c qmake and your make tool to build a + plugin that integrates the QAxContainer module into \l{Qt + Designer}. + + The ActiveQt modules are part of the \l{Qt Commercial Edition} and + the \l{Open Source Versions of Qt}. + + \sa {QAxContainer Module}, {QAxServer Module} +*/ diff --git a/doc/src/examples/comapp.qdoc b/doc/src/examples/comapp.qdoc new file mode 100644 index 0000000..4e4b9cb --- /dev/null +++ b/doc/src/examples/comapp.qdoc @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example activeqt/comapp + \title COM App Example (ActiveQt) + + The COM App example shows how to use ActiveQt to develop a Qt + application that can be automated via COM. Different QObject + based classes are exposed as COM objects that communicate with the + GUI of the running Qt application. The APIs of those COM objects + has been designed to resemble the APIs of standard COM + applications; i.e. those from Microsoft Office. + + \snippet examples/activeqt/comapp/main.cpp 2 + The first class \c Application represents the application object. It + exposes read-only properties \c documents and \c id to get access to the + list of documents, and an identifier. A read/write property \c visible + controls whether the QTabWidget-based user interface of the application + should be visible, and a slot \c quit() terminates the application. + + The \e RegisterObject attribute is set to make sure that instances of this + class are registered in COM's running object table (ROT) - this allows COM + clients to connect to an already instantiated COM object. + + \snippet examples/activeqt/comapp/main.cpp 1 + The \c DocumentList class stores a list of documents. It provides an API + to read the number of documents, to access each document by index and to + create a new document. The \c application property returns the root object. + + \snippet examples/activeqt/comapp/main.cpp 0 + + The \c Document class finally represents a document in the application. + Each document is represented by a page in the application's tab widget, and + has a title that is readable and writable through the document's API. + The \c application property again returns the root object. + + \snippet examples/activeqt/comapp/main.cpp 3 + The implementation of the \c Document class creates a new page for the tab + widget, and uses the title of that page for the title property. The page + is deleted when the document is deleted. + + \snippet examples/activeqt/comapp/main.cpp 4 + The \c DocumentList implementation is straightforward. + + \snippet examples/activeqt/comapp/main.cpp 5 + The \c Application class initializes the user interface in the constructor, + and shows and hides it in the implementation of \c setVisible(). The object + name (accessible through the \c id property) is set to \c "From QAxFactory" + to indicate that this COM object has been created by COM. Note that there is + no destructor that would delete the QTabWidget - this is instead done in the + \c quit() slot, before calling QApplication::quit() through a single-shot-timer, + which is necessary ensure that the COM call to the slot is complete. + + \snippet examples/activeqt/comapp/main.cpp 6 + The classes are exported from the server using the QAxFactory macros. Only + \c Application objects can be instantiated from outside - the other APIs can + only be used after accessing the respective objects throught the \c Application + API. + + \snippet examples/activeqt/comapp/main.cpp 7 + The main() entry point function creates a QApplication, and just enters the + event loop if the application has been started by COM. If the application + has been started by the user, then the \c Application object is created and + the object name is set to "From Application". Then the COM server is started, + and the application object is registered with COM. It is now accessible to + COM clients through the client-specific APIs. + + Application exiting is controlled explicitly - if COM started the application, + then the client code has to call quit(); if the user started the application, + then the application terminates when the last window has been closed. + + Finally, the user interface is made visible, and the event loop is started. + + A simple Visual Basic application could now access this Qt application. In VB, + start a new "Standard Exe" project and add a project reference to the comappLib + type library. Create a form with a listbox "DocumentList", a static label + "DocumentsCount" and a command button "NewDocument". Finally, implement the code + for the form like this: + + \snippet doc/src/snippets/code/doc_src_examples_activeqt_comapp.qdoc 0 + + To build the example you must first build the QAxServer library. + Then run \c qmake and your make tool in + \c{examples\activeqt\comapp}. +*/ diff --git a/doc/src/examples/dotnet.qdoc b/doc/src/examples/dotnet.qdoc new file mode 100644 index 0000000..ec13ce8 --- /dev/null +++ b/doc/src/examples/dotnet.qdoc @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page activeqt-dotnet.html + \title Dot Net Example (ActiveQt) + + The Dot Net example demonstrates how Qt objects can be used in a + .NET environment, and how .NET objects can be used in a Qt + environment. + + If you need to combine Qt and Win Forms widgets in the same + application, you might want to use the higher-level + \l{QtWinForms Solution} instead. + + Contents: + + \tableofcontents + + \section1 Qt vs. .NET + + Qt is a C++ library and is compiled into traditional, native + binaries that make full use of the performance provided by the + runtime environment. + + One of the key concepts of .NET is the idea of "intermediate language + code" - the source code is compiled into a bytecode format, and at + runtime, that bytecode is executed in a virtual machine - the \e + {Common Language Runtime} (CLR). + + Another key concept is that of \e {managed code}. This is essentially + intermediate language code written in such a way that the CLR can take + care of the memory management, i.e. the CLR will do automatic garbage + collection, so the application code does not need to explicitly free + the memory for unused objects. + + The MS compilers for C# and VB.NET will only produce managed + code. Such programs cannot directly call normal, native functions + or classes. \footnote The .NET framework provides Platform Invocation + Services - P/Invoke - that enable managed code to call native C (not + C++) functions located in DLLs directly. The resulting application + then becomes partially unmanaged.\endfootnote + + The MS C++ compiler for .NET on the other hand, can produce both + normal and managed code. To write a C++ class that can be compiled + into managed code, the developer must flag the class as managed using + the \c __gc keyword, and restrict the code to only use the subset of + C++ known as "Managed Extensions for C++", or MC++ for short. The + advantage is that MC++ code can freely call and use normal C++ + functions and classes. And it also works the other way around: normal + C++ code can call managed functions and use managed classes (e.g. the + entire .NET framework class library), including managed functions and + classes implemented in C# or VB.NET. This feature of mixing managed + and normal C++ code immensely eases the interoperability with .NET, + and is by Microsoft referred to as the "It Just Works" (IJW) feature. + + This document demonstrates two different ways of integrating normal + C++ code (that uses Qt) with managed .NET code. First, the manual way + is presented, which includes using a thin MC++ wrapper class around + the normal Qt/C++ class. Then, the automated way is presented, which + utilizes the ActiveQt framework as a generic bridge. The advantage of + the first method is that it gives the application developer full + control, while the second method requires less coding and relieves the + developer of dealing with the conversion between managed and normal + data objects. + + The impatient reader, who right away wants to see a QPushButton + and a custom Qt widget (\l{activeqt/multiple}{QAxWidget2}) run in + a .NET GUI application is referred to the example directory of + ActiveQt. It contains the result of this walkthrough using both + C# and VB.NET, created with Visual Studio .NET (not 2003). + Load \c {examples/dotnet/walkthrough/csharp.csproj}, + \c {examples/dotnet/walkthrough/vb.vbproj} + or \c {examples/dotnet/wrapper/wrapper.sln} into the IDE and run + the solution. + + \bold{Remark:} You will notice that in the generated code the following line is + commented out: + + \snippet doc/src/snippets/code/doc_src_examples_activeqt_dotnet.qdoc 0 + + This line is regenerated without comment whenever you change the + dialog, in which case you have to comment it out again to be able + to run the project. This is a bug in the original version of + Visual Studio.NET, and is fixed in the 2003 edition. + + \section1 Walkthrough: .NET interop with MC++ and IJW + + Normal C++ classes and functions can be used from managed .NET code by + providing thin wrapper classes written in MC++. The wrapper class will + take care of forwarding the calls to the normal C++ functions or + methods, and converting parameter data as necessary. Since the wrapper + class is a managed class, it can be used without further ado in any + managed .NET application, whether written in C#, VB.NET, MC++ or other + managed programming language. + + \snippet examples/activeqt/dotnet/wrapper/lib/worker.h 0 + + The Qt class has nothing unusual for Qt users, and as even the Qt + specialities like \c Q_PROPERTY, \c slots and \c signals are + implemented with straight C++ they don't cause any trouble when + compiling this class with any C++ compiler. + + \snippet examples/activeqt/dotnet/wrapper/lib/networker.h 0 + + The .NET wrapper class uses keywords that are part of MC++ to indicate + that the class is managed/garbage collected (\c {__gc}), and that \c + StatusString should be accessible as a property in languages that + support this concept (\c {__property}). We also declare an event + function \c statusStringChanged(String*) (\c {__event}), the + equivalent of the respective signal in the Qt class. + + Before we can start implementing the wrapper class we need a way to + convert Qt's datatypes (and potentionally your own) into .NET + datatypes, e.g. \c QString objects need to be converted into objects + of type \c {String*}. + + When operating on managed objects in normal C++ code, a little extra + care must be taken because of the CLR's garbage collection. A normal + pointer variable should not \footnote Indeed, the compiler will in + many cases disallow it. \endfootnote be used to refer to a managed + object. The reason is that the garbage collection can kick in at any + time and move the object to another place on the heap, leaving you + with an invalid pointer. + + However, two methods are provided that solves this problem easily. The + first is to use a \e pinned pointer, i.e. declare the pointer variable + with the \c __pin keyword. This guarantees that the object pointed to + will not be moved by the garbage collector. It is recommended that + this method not be used to keep a references to managed objects for a + long time, since it will decrease the efficiency of the garbage + collector. The second way is to use the \c gcroot smartpointer + template type. This lets you create safe pointers to managed + objects. E.g. a variable of type \c gcroot<String> will always point + to the String object, even if it has been moved by the garbage + collector, and it can be used just like a normal pointer. + + \snippet examples/activeqt/dotnet/wrapper/lib/tools.cpp 0 + \codeline + \snippet examples/activeqt/dotnet/wrapper/lib/tools.cpp 1 + + The convertor functions can then be used in the wrapper class + implementation to call the functions in the native C++ class. + + \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 0 + \codeline + \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 1 + + The constructor and destructor simply create and destroy the Qt + object wrapped using the C++ operators \c new and \c delete. + + \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 2 + + The netWorker class delegates calls from the .NET code to the native + code. Although the transition between those two worlds implies a small + performance hit for each function call, and for the type conversion, + this should be negligible since we are anyway going to run within the + CLR. + + \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 3 + + The property setter calls the native Qt class before firing the + event using the \c __raise keyword. + + This wrapper class can now be used in .NET code, e.g. using C++, C#, + Visual Basic or any other programming language available for .NET. + + \snippet examples/activeqt/dotnet/wrapper/main.cs 0 + \snippet examples/activeqt/dotnet/wrapper/main.cs 1 + \snippet examples/activeqt/dotnet/wrapper/main.cs 2 + \snippet examples/activeqt/dotnet/wrapper/main.cs 3 + + \section1 Walkthrough: .NET/COM Interop with ActiveQt + + Fortunately .NET provides a generic wrapper for COM objects, the + \e {Runtime Callable Wrapper} (RCW). This RCW is a proxy for the + COM object and is generated by the CLR when a .NET Framework client + activates a COM object. This provides a generic way to reuse COM + objects in a .NET Framework project. + + Making a QObject class into a COM object is easily achieved with + ActiveQt and demonstrated in the QAxServer examples (e.g., the + \l{activeqt/simple}{Simple} example). The walkthrough will use + the Qt classes implemented in those examples, so the first thing + to do is to make sure that those examples have been built + correctly, e.g. by opening the + \l{qaxserver-demo-multiple.html}{demonstration pages} in Internet + Explorer to verify that the controls are functional. + + \section2 Starting a Project + + Start Visual Studio.NET, and create a new C# project for writing a + Windows application. This will present you with an empty form in + Visual Studio's dialog editor. You should see the toolbox, which + presents you with a number of available controls and objects in + different categories. If you right-click on the toolbox it allows + you to add new tabs. We will add the tab "Qt". + + \section2 Importing Qt Widgets + + The category only has a pointer tool by default, and we have to add + the Qt objects we want to use in our form. Right-click on the empty + space, and select "Customize". This opens a dialog that has two + tabs, "COM Components" and ".NET Framework Components". We used + ActiveQt to wrap QWidgets into COM objects, so we select the "COM + Components" page, and look for the classes we want to use, e.g. + "QPushButton" and "QAxWidget2". + + When we select those widgets and close the dialog the two widgets + will now be available from the toolbox as grey squares with their + name next to it \footnote Icons could be added by modifying the + way the controls register themselves. \endfootnote. + + \section2 Using Qt Widgets + + We can now add an instance of QAxWidget2 and a QPushButton to + the form. Visual Studio will automatically generate the RCW for the + object servers. The QAxWidget2 instance takes most of the upper + part of the form, with the QPushButton in the lower right corner. + + In the property editor of Visual Studio we can modify the properties + of our controls - QPushButton exposes the \c QWidget API and has many + properties, while QAxWidget2 has only the Visual Studio standard + properties in addition to its own property "lineWidth" in the + "Miscellaneous" category. The objects are named "axQPushButton1" and + "axQAxWidget21", and since especially the last name is a bit + confusing we rename the objects to "resetButton" and "circleWidget". + + We can also change the Qt properties, e.g. set the "text" property + of the \c resetButton to "Reset", and the "lineWidth" property of the + \c circleWidget to 5. We can also put those objects into the layout + system that Visual Studio's dialog editor provides, e.g. by setting + the anchors of the \c circleWidget to "Left, Top, Right, Bottom", and + the anchors of the \c resetButton to "Bottom, Right". + + Now we can compile and start the project, which will open a user + interface with our two Qt widgets. If we can resize the dialog, + the widgets will resize appropriately. + + \section2 Handling Qt Signals + + We will now implement event handlers for the widgets. Select the + \c circleWidget and select the "Events" page in the property + editor. The widget exposes events because the QAxWidget2 class has + the "StockEvents" attribute set in its class definition. We implement + the event handler \c circleClicked for the \c ClickEvent to increase + the line width by one for every click: + + \snippet examples/activeqt/dotnet/walkthrough/Form1.cs 0 + + In general we can implement a default event handler by double + clicking on the widget in the form, but the default events for + our widgets are right now not defined. + + We will also implement an event handler for the \c clicked signal + emitted by QPushButton. Add the event handler \c resetLineWidth to + the \c clicked event, and implement the generated function: + + \snippet examples/activeqt/dotnet/walkthrough/Form1.cs 1 + + We reset the property to 1, and also call the \c setFocus() slot + to simulate the user style on Windows, where a button grabs focus + when you click it (so that you can click it again with the spacebar). + + If we now compile and run the project we can click on the circle + widget to increase its line width, and press the reset button to + set the line width back to 1. + + \section1 Summary + + Using ActiveQt as a universal interoperability bridge between the + .NET world and the native world of Qt is very easy, and makes it + often unnecessary to implement a lot of handwritten wrapper classes. + Instead, the QAxFactory implementation in the otherwise completely + cross-platform Qt project provides the glue that .NET needs to to + generate the RCW. + + If this is not sufficient we can implement our own wrapper classes + thanks to the C++ extensions provided by Microsoft. + + \section2 Limitations + + All the limitations when using ActiveQt are implied when using this + technique to interoperate with .NET, e.g. the datatypes we can use + in the APIs can only be those supported by ActiveQt and COM. However, + since this includes subclasses of QObject and QWidget we can wrap + any of our datatypes into a QObject subclass to make its API + available to .NET. This has the positive side effect that the same + API is automatically available in + \l{http://qt.nokia.com/products/qsa/}{QSA}, the cross platform + scripting solution for Qt applications, and to COM clients in general. + + When using the "IJW" method, in priciple the only limitation is the + time required to write the wrapper classes and data type conversion + functions. + + \section2 Performance Considerations + + Every call from CLR bytecode to native code implies a small + performance hit, and necessary type conversions introduce an + additional delay with every layer that exists between the two + frameworks. Consequently every approach to mix .NET and native + code should try to minimize the communication necessary between + the different worlds. + + As ActiveQt introduces three layers at once - the RCW, COM and finally + ActiveQt itself - the performance penalty when using the generic + Qt/ActiveQt/COM/RCW/.NET bridge is larger than when using a + hand-crafted IJW-wrapper class. The execution speed however is still + sufficient for connecting to and modifying interactive elements in a + user interface, and as soon as the benefit of using Qt and C++ to + implement and compile performance critical algorithms into native code + kicks in, ActiveQt becomes a valid choice for making even non-visual + parts of your application accessible to .NET. + + \sa {QtWinForms Solution} +*/ diff --git a/doc/src/examples/hierarchy-demo-snippet.qdoc b/doc/src/examples/hierarchy-demo-snippet.qdoc new file mode 100644 index 0000000..a36ebbb --- /dev/null +++ b/doc/src/examples/hierarchy-demo-snippet.qdoc @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [script] +<script language="javascript"> +function createSubWidget( form ) +{ + ParentWidget.createSubWidget( form.nameEdit.value ); +} + +function renameSubWidget( form ) +{ + var SubWidget = ParentWidget.subWidget( form.nameEdit.value ); + if ( !SubWidget ) { + alert( "No such widget " + form.nameEdit.value + "!" ); + return; + } + SubWidget.label = form.labelEdit.value; + form.nameEdit.value = SubWidget.label; +} + +function setFont( form ) +{ + ParentWidget.font = form.fontEdit.value; +} +</script> + +<p> +This widget can have many children! +</p> +<object ID="ParentWidget" CLASSID="CLSID:d574a747-8016-46db-a07c-b2b4854ee75c" +CODEBASE="http://qt.nokia.com/demos/hierarchy.cab"> +[Object not available! Did you forget to build and register the server?] +</object><br /> +<form> +<input type="edit" ID="nameEdit" value="<enter object name>" /> +<input type="button" value="Create" onClick="createSubWidget(this.form)" /> +<input type="edit" ID="labelEdit" /> +<input type="button" value="Rename" onClick="renameSubWidget(this.form)" /> +<br /> +<input type="edit" ID="fontEdit" value="MS Sans Serif" /> +<input type="button" value = "Set Font" onClick="setFont(this.form)" /> +</form> +//! [script] diff --git a/doc/src/examples/hierarchy-demo.qdocinc b/doc/src/examples/hierarchy-demo.qdocinc new file mode 100644 index 0000000..86bfd87 --- /dev/null +++ b/doc/src/examples/hierarchy-demo.qdocinc @@ -0,0 +1,41 @@ +\raw HTML +<script language="javascript"> +function createSubWidget( form ) +{ + ParentWidget.createSubWidget( form.nameEdit.value ); +} + +function renameSubWidget( form ) +{ + var SubWidget = ParentWidget.subWidget( form.nameEdit.value ); + if ( !SubWidget ) { + alert( "No such widget " + form.nameEdit.value + "!" ); + return; + } + SubWidget.label = form.labelEdit.value; + form.nameEdit.value = SubWidget.label; +} + +function setFont( form ) +{ + ParentWidget.font = form.fontEdit.value; +} +</script> + +<p> +This widget can have many children! +</p> +<object ID="ParentWidget" CLASSID="CLSID:d574a747-8016-46db-a07c-b2b4854ee75c" +CODEBASE="http://qt.nokia.com/demos/hierarchy.cab"> +[Object not available! Did you forget to build and register the server?] +</object><br /> +<form> +<input type="edit" ID="nameEdit" value="<enter object name>" /> +<input type="button" value="Create" onClick="createSubWidget(this.form)" /> +<input type="edit" ID="labelEdit" /> +<input type="button" value="Rename" onClick="renameSubWidget(this.form)" /> +<br /> +<input type="edit" ID="fontEdit" value="MS Sans Serif" /> +<input type="button" value = "Set Font" onClick="setFont(this.form)" /> +</form> +\endraw diff --git a/doc/src/examples/hierarchy.qdoc b/doc/src/examples/hierarchy.qdoc new file mode 100644 index 0000000..791af1f --- /dev/null +++ b/doc/src/examples/hierarchy.qdoc @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qaxserver-demo-hierarchy.html + \title Qt Widget Hierarchy + + \input examples/activeqt/hierarchy-demo.qdocinc +*/ + +/*! + \example activeqt/hierarchy + \title Hierarchy Example (ActiveQt) + + The Hierarchy example is shows how to write an in-process ActiveX + control. The control is a QWidget subclass with child widgets + that are accessible as sub-types. + + \snippet examples/activeqt/hierarchy/objects.h 0 + The \c QParentWidget class provides slots to create a widget + with a name, and to return a pointer to a named widget. The class + declaration uses \c Q_CLASSINFO() to provide the COM identifiers for + this class. + + \snippet examples/activeqt/hierarchy/objects.cpp 0 + The constructor of QParentWidget creates a vertical box layout. + New child widgets are automatically added to the layout. + + \snippet examples/activeqt/hierarchy/objects.cpp 1 + The \c createSubWidget slot creates a new \c QSubWidget with + the name provided in the parameter, and sets the label to that + name. The widget is also shown explicitly. + + \snippet examples/activeqt/hierarchy/objects.cpp 2 + The \c subWidget slot uses the \c QObject::child() function and + returns the first child of type \c QSubWidget that has the requested + name. + + \snippet examples/activeqt/hierarchy/objects.h 1 + The \c QSubWidget class has a single string-property \c label, + and implements the paintEvent to draw the label. The class uses + again \c Q_CLASSINFO to provide the COM identifiers, and also sets + the \e ToSuperClass attribute to \e QSubWidget, to ensure that only + no slots of any superclasses (i.e. QWidget) are exposed. + + \snippet examples/activeqt/hierarchy/objects.cpp 3 + \snippet examples/activeqt/hierarchy/objects.cpp 4 + The implementation of the QSubWidget class is self-explanatory. + + \snippet examples/activeqt/hierarchy/main.cpp 0 + The classes are then exported using a QAxFactory. \c QParentWidget is + exported as a full class (which can be created ), while \c QSubWidget is + only exported as a type, which can only be created indirectly through + APIs of \c QParentWidget. + + To build the example you must first build the QAxServer library. + Then run qmake and your make tool in \c examples/activeqt/hierarchy. + + The \l{qaxserver-demo-hierarchy.html}{demonstration} requires + your WebBrowser to support ActiveX controls, and scripting to be + enabled. + + \snippet examples/activeqt/hierarchy-demo-snippet.qdoc script +*/ diff --git a/doc/src/examples/menus.qdoc b/doc/src/examples/menus.qdoc new file mode 100644 index 0000000..5cbf063 --- /dev/null +++ b/doc/src/examples/menus.qdoc @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qaxserver-demo-menus.html + \preliminary + + \title Menubar Merging + + This example is not full functional at the moment. + + \raw HTML + <object ID="QMenus" CLASSID="CLSID:4dc3f340-a6f7-44e4-a79b-3e9217695fbd" + CODEBASE="http://qt.nokia.com/demos/menusax.cab"> + [Object not available! Did you forget to build and register the server?] + </object> + \endraw +*/ + +/*! + \example activeqt/menus + \title Menus Example (ActiveQt) + + The Menus example demonstrates the use of QMenuBar and QStatusBar + in a QMainWindow to implement an in-place active control. + + To build the example you must first build the QAxServer library. + Then run \c qmake and your make tool in \c + examples/activeqt/menus. + + The \l{qaxserver-demo-menus.html}{demonstration} requires your + WebBrowser to support ActiveX controls, and scripting to be + enabled. + + \snippet doc/src/snippets/code/doc_src_examples_activeqt_menus.qdoc 0 +*/ diff --git a/doc/src/examples/multiple-demo.qdocinc b/doc/src/examples/multiple-demo.qdocinc new file mode 100644 index 0000000..339fc20 --- /dev/null +++ b/doc/src/examples/multiple-demo.qdocinc @@ -0,0 +1,39 @@ +\raw HTML +//! [0] +<script language="javascript"> +function setColor( form ) +{ + Ax1.fillColor = form.colorEdit.value; +} + +function setWidth( form ) +{ + Ax2.lineWidth = form.widthEdit.value; +} +</script> + +<p /> +This is one QWidget subclass:<br /> +<object ID="Ax1" CLASSID="CLSID:1D9928BD-4453-4bdd-903D-E525ED17FDE5" +CODEBASE="http://qt.nokia.com/demos/multipleax.cab"> +[Object not available! Did you forget to build and register the server?] +</object><br /> +<form> +Fill Color: <input type="edit" ID="colorEdit" value = "red" /> +<input type="button" value = "Set" onClick="setColor(this.form)" /> +<input type="button" value = "Hide" onClick="Ax1.hide()" /> +<input type="button" value = "Show" onClick="Ax1.show()" /> +</form> + +<p /> +This is another QWidget subclass:<br /> +<object ID="Ax2" CLASSID="CLSID:58139D56-6BE9-4b17-937D-1B1EDEDD5B71" +CODEBASE="http://qt.nokia.com/demos/multipleax.cab"> +[Object not available! Did you forget to build and register the server?] +</object><br /> +<form> +Line width: <input type="edit" ID="widthEdit" value = "1" /> +<input type="button" value = "Set" onClick="setWidth(this.form)" /> +</form> +//! [0] +\endraw diff --git a/doc/src/examples/multiple.qdoc b/doc/src/examples/multiple.qdoc new file mode 100644 index 0000000..1f58dcc --- /dev/null +++ b/doc/src/examples/multiple.qdoc @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qaxserver-demo-multiple.html + \title Two Simple Qt Widgets + + \input examples/activeqt/multiple-demo.qdocinc +*/ + +/*! + \example activeqt/multiple + \title Multiple Example (ActiveQt) + + The Multiple example demonstrates the implementation of a + QAxFactory to provide multiple ActiveX controls in a single in + process ActiveX server using the \c QAXFACTORY_EXPORT() macro. + The ActiveX controls in this example are simple QWidget + subclasses that reimplement QWidget::paintEvent(). + + \snippet examples/activeqt/multiple/ax1.h 0 + + The first control draws a filled rectangle. The fill color is exposed + as a property. \c Q_CLASSINFO() is used to specify the COM identifiers. + + \snippet examples/activeqt/multiple/ax2.h 0 + + The second control draws a circle. The linewith is exposed as a property. + \c Q_CLASSINFO() is used to specify the COM identifiers, and to set the + attributes \e ToSuperClass and \e StockEvents to expose only the API of + the class itself, and to add COM stock events to the ActiveX control. + + \snippet examples/activeqt/multiple/main.cpp 0 + + The classes are exported from the server using the QAxFactory macros. + + To build the example you must first build the QAxServer library. + Then run \c qmake and your make tool in \c + examples/activeqt/multiple. + + The \l{qaxserver-demo-multiple.html}{demonstration} requires your + WebBrowser to support ActiveX controls, and scripting to be + enabled. + + \snippet examples/activeqt/multiple-demo.qdocinc 0 +*/ diff --git a/doc/src/examples/opengl-demo.qdocinc b/doc/src/examples/opengl-demo.qdocinc new file mode 100644 index 0000000..ccc1452 --- /dev/null +++ b/doc/src/examples/opengl-demo.qdocinc @@ -0,0 +1,27 @@ +\raw HTML +//! [0] +<SCRIPT LANGUAGE="JavaScript"> +function setRot( form ) +{ + GLBox.setXRotation( form.XEdit.value ); + GLBox.setYRotation( form.YEdit.value ); + GLBox.setZRotation( form.ZEdit.value ); +} +</SCRIPT> + +<p /> +An OpenGL scene:<br /> +<object ID="GLBox" CLASSID="CLSID:5fd9c22e-ed45-43fa-ba13-1530bb6b03e0" +CODEBASE="http://qt.nokia.com/demos/openglax.cab"> +[Object not available! Did you forget to build and register the server?] +</object><br /> + +<form> +Rotate the scene:<br /> +X:<input type="edit" ID="XEdit" value="0" /><br /> +Y:<input type="edit" name="YEdit" value="0" /><br /> +Z:<input type="edit" name="ZEdit" value="0" /><br /> +<input type="button" value="Set" onClick="setRot(this.form)" /> +</form> +//! [0] +\endraw diff --git a/doc/src/examples/opengl.qdoc b/doc/src/examples/opengl.qdoc new file mode 100644 index 0000000..4f64eff --- /dev/null +++ b/doc/src/examples/opengl.qdoc @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qaxserver-demo-opengl.html + + \title OpenGL in an HTML page + + \raw HTML + <SCRIPT LANGUAGE="JavaScript"> + function setRot( form ) + { + GLBox.setXRotation( form.XEdit.value ); + GLBox.setYRotation( form.YEdit.value ); + GLBox.setZRotation( form.ZEdit.value ); + } + </SCRIPT> + + <p /> + An OpenGL scene:<br /> + <object ID="GLBox" CLASSID="CLSID:5fd9c22e-ed45-43fa-ba13-1530bb6b03e0" + CODEBASE="http://qt.nokia.com/demos/openglax.cab"> + [Object not available! Did you forget to build and register the server?] + </object><br /> + + <form> + Rotate the scene:<br /> + X:<input type="edit" ID="XEdit" value="0" /><br /> + Y:<input type="edit" name="YEdit" value="0" /><br /> + Z:<input type="edit" name="ZEdit" value="0" /><br /> + <input type="button" value="Set" onClick="setRot(this.form)" /> + </form> + \endraw +*/ + +/*! + \example activeqt/opengl + \title OpenGL Example (ActiveQt) + + The OpenGL example demonstrates the use of the default factory + and QAxFactory::isServer(), and the implementation of an + additional COM interface using QAxBindable and QAxAggregated. + The server executable can run both as an ActiveX server and as a + stand-alone application. + + The ActiveX control in this example uses the QGlWidget class in + Qt to render an OpenGL scene in an ActiveX. The control exposes a few + methods to change the scene. + + The application uses the default factory as provided by the + QAXFACTORY_DEFAULT macro to expose the \c GLBox widget as an ActiveX + control. + \snippet examples/activeqt/opengl/main.cpp 0 + The implementation of \c main initializes the QApplication object, + and uses \c QAxFactory::isServer() to determine whether or not it is + appropriate to create and show the application interface. + \snippet examples/activeqt/opengl/main.cpp 1 + \snippet examples/activeqt/opengl/main.cpp 2 + \snippet examples/activeqt/opengl/main.cpp 3 + + The \c GLBox class inherits from both the \l QGLWidget class to be able + to render OpenGL, and from \l QAxBindable. + \snippet examples/activeqt/opengl/glbox.h 0 + The class reimplements the \l QAxBindable::createAggregate() function from QAxBindable + to return the pointer to a \l QAxAggregated object. + \snippet examples/activeqt/opengl/glbox.h 1 + The rest of the class declaration and the implementation of the OpenGL + rendering is identical to the original "box" example. + + The implementation file of the \c GLBox class includes the \c objsafe.h + system header, in which the \c IObjectSafety COM interface is defined. + \snippet examples/activeqt/opengl/glbox.cpp 0 + A class \c ObjectSafetyImpl is declared using multiple inheritance + to subclass the QAxAggregated class, and to implement the IObjectSafety + interface. + \snippet examples/activeqt/opengl/glbox.cpp 1 + The class declares a default constructor, and implements the queryInterface + function to support the IObjectSafety interface. + \snippet examples/activeqt/opengl/glbox.cpp 2 + Since every COM interface inherits \c IUnknown the \c QAXAGG_IUNKNOWN macro + is used to provide the default implementation of the \c IUnknown interface. + The macro is defined to delegate all calls to \c QueryInterface, \c AddRef + and \c Release to the interface returned by the controllingUnknown() function. + \snippet examples/activeqt/opengl/glbox.cpp 3 + The implementation of the \c IObjectSafety interface provides the caller + with information about supported and enabled safety options, and returns + \c S_OK for all calls to indicate that the ActiveX control is safe. + \snippet examples/activeqt/opengl/glbox.cpp 4 + The implementation of the \c createAggregate() function just returns a new + \c ObjectSafetyImpl object. + \snippet examples/activeqt/opengl/glbox.cpp 5 + + To build the example you must first build the QAxServer library. + Then run \c qmake and your make tool in \c + examples/activeqt/wrapper. + + The \l{qaxserver-demo-opengl.html}{demonstration} requires your + WebBrowser to support ActiveX controls, and scripting to be + enabled. + + In contrast to the other QAxServer examples Internet Explorer will not + open a dialog box to ask the user whether or not the scripting of the GLBox + control should be allowed (the exact browser behaviour depends on the security + settings in the Internet Options dialog). + + \snippet doc/src/examples/activeqt/opengl-demo.qdocinc 0 +*/ diff --git a/doc/src/examples/qutlook.qdoc b/doc/src/examples/qutlook.qdoc new file mode 100644 index 0000000..e701c59 --- /dev/null +++ b/doc/src/examples/qutlook.qdoc @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example activeqt/qutlook + \title Qutlook Example (ActiveQt) + + The Qutlook example demonstrates the use of ActiveQt to automate + Outlook. The example makes use of the \l dumpcpp tool to generate + a C++ namespace for the type library describing the Outlook + Object Model. + + The project file for the example looks like this: + + \snippet examples/activeqt/qutlook/qutlook.pro 1 + \snippet examples/activeqt/qutlook/qutlook.pro 2 + + The project file uses the \c dumpcpp tool to add an MS Outlook type library to the project. + If this fails, then the generated makefile will just print an error message, otherwise + the build step will now run the \e dumpcpp tool on the type library, and + generate a header and a cpp file (in this case, \c msoutl.h and \c msoutl.cpp) that + declares and implement an easy to use API to the Outlook objects. + + \snippet examples/activeqt/qutlook/addressview.h 0 + + The AddressView class is a QWidget subclass for the user interface. The QTreeView widget + will display the contents of Outlook's Contact folder as provided by the \c{model}. + + \snippet examples/activeqt/qutlook/addressview.cpp 0 + The AddressBookModel class is a QAbstractListModel subclass that communicates directly with + Outlook, using a QHash for caching. + + \snippet examples/activeqt/qutlook/addressview.cpp 1 + The constructor initializes Outlook. The various signals Outlook provides to notify about + contents changes are connected to the \c updateOutlook() slot. + + \snippet examples/activeqt/qutlook/addressview.cpp 2 + The destructor logs off from the session. + + \snippet examples/activeqt/qutlook/addressview.cpp 3 + The \c rowCount() implementation returns the number of entries as reported by Outlook. \c columnCount + and \c headerData are implemented to show four columns in the tree view. + + \snippet examples/activeqt/qutlook/addressview.cpp 4 + The \c headerData() implementation returns hardcoded strings. + + \snippet examples/activeqt/qutlook/addressview.cpp 5 + The \c data() implementation is the core of the model. If the requested data is in the cache the + cached value is used, otherwise the data is acquired from Outlook. + + \snippet examples/activeqt/qutlook/addressview.cpp 6 + The \c changeItem() slot is called when the user changes the current entry using the user interface. + The Outlook item is accessed using the Outlook API, and is modified using the property setters. + Finally, the item is saved to Outlook, and removed from the cache. Note that the model does not + signal the view of the data change, as Outlook will emit a signal on its own. + + \snippet examples/activeqt/qutlook/addressview.cpp 7 + The \c addItem() slot calls the CreateItem method of Outlook to create a new contact item, + sets the properties of the new item to the values entered by the user and saves the item. + + \snippet examples/activeqt/qutlook/addressview.cpp 8 + The \c update() slot clears the cache, and emits the reset() signal to notify the view about the + data change requiring a redraw of the contents. + + \snippet examples/activeqt/qutlook/addressview.cpp 9 + \snippet examples/activeqt/qutlook/addressview.cpp 10 + The rest of the file implements the user interface using only Qt APIs, i.e. without communicating + with Outlook directly. + + \snippet examples/activeqt/qutlook/main.cpp 0 + + The \c main() entry point function finally instantiates the user interface and enters the + event loop. + + To build the example you must first build the QAxContainer + library. Then run your make tool in \c examples/activeqt/qutlook + and run the resulting \c qutlook.exe. +*/ diff --git a/doc/src/examples/simple-demo.qdocinc b/doc/src/examples/simple-demo.qdocinc new file mode 100644 index 0000000..5eee8bc --- /dev/null +++ b/doc/src/examples/simple-demo.qdocinc @@ -0,0 +1,45 @@ +\raw HTML +//! [0] +<object ID="QSimpleAX" CLASSID="CLSID:DF16845C-92CD-4AAB-A982-EB9840E74669" +CODEBASE="http://qt.nokia.com/demos/simpleax.cab"> + <PARAM NAME="text" VALUE="A simple control" /> + <PARAM NAME="value" VALUE="1" /> +[Object not available! Did you forget to build and register the server?] +</object> +//! [0] //! [1] + +<FORM> + <INPUT TYPE="BUTTON" VALUE="About..." onClick="QSimpleAX.about()" /> +</FORM> +//! [1] + +//! [2] +<object ID="Calendar" CLASSID="CLSID:8E27C92B-1264-101C-8A2F-040224009C02"> +[Standard Calendar control not available!] + <PARAM NAME="day" VALUE="1" /> +</object> +//! [2] + +<FORM> + <INPUT TYPE="BUTTON" VALUE="Today" onClick="Calendar.Today()" /> +</FORM> + +//! [3] +<SCRIPT LANGUAGE="VBScript"> +Sub Calendar_Click() + MsgBox( "Calendar Clicked!" ) +End Sub + +Sub QSimpleAX_TextChanged( str ) + document.title = str +End Sub +</SCRIPT> + +<SCRIPT LANGUAGE="JavaScript"> +function QSimpleAX::ValueChanged( Newvalue ) +{ + Calendar.Day = Newvalue; +} +</SCRIPT> +//! [3] +\endraw diff --git a/doc/src/examples/simple.qdoc b/doc/src/examples/simple.qdoc new file mode 100644 index 0000000..b0e942f --- /dev/null +++ b/doc/src/examples/simple.qdoc @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qaxserver-demo-simple.html + + \title A standard ActiveX and the "simple" ActiveQt widget + + \raw HTML + <object ID="QSimpleAX" CLASSID="CLSID:DF16845C-92CD-4AAB-A982-EB9840E74669" + CODEBASE="http://qt.nokia.com/demos/simpleax.cab"> + <PARAM NAME="text" VALUE="A simple control" /> + <PARAM NAME="value" VALUE="1" /> + [Object not available! Did you forget to build and register the server?] + </object> + + <FORM> + <INPUT TYPE="BUTTON" VALUE="About..." onClick="QSimpleAX.about()" /> + </FORM> + + <object ID="Calendar" CLASSID="CLSID:8E27C92B-1264-101C-8A2F-040224009C02"> + [Standard Calendar control not available!] + <PARAM NAME="day" VALUE="1" /> + </object> + + <FORM> + <INPUT TYPE="BUTTON" VALUE="Today" onClick="Calendar.Today()" /> + </FORM> + + <SCRIPT LANGUAGE="VBScript"> + Sub Calendar_Click() + MsgBox( "Calendar Clicked!" ) + End Sub + + Sub QSimpleAX_TextChanged( str ) + document.title = str + End Sub + </SCRIPT> + + <SCRIPT LANGUAGE="JavaScript"> + function QSimpleAX::ValueChanged( Newvalue ) + { + Calendar.Day = Newvalue; + } + </SCRIPT> + \endraw +*/ + +/*! + \example activeqt/simple + \title Simple Example (ActiveQt) + + The Simple example demonstrates the use of + QAxBindable::requestPropertyChange() and + QAxBindable::propertyChanged(), and the use of the default + QAxFactory through the \c QAXFACTORY_DEFAULT() macro. + + The ActiveX control in this example is a laid out QWidget with a + QSlider, a QLCDNumber and a QLineEdit. It provides a + signal/slot/property interface to change the values of the slider + and the line edit, and to get notified of any property changes. + + + The Qt implementation of the ActiveX for this example is + \snippet examples/activeqt/simple/main.cpp 0 + + The control is exported using the default QAxFactory + \snippet examples/activeqt/simple/main.cpp 1 + + To build the example you must first build the QAxServer library. + Then run qmake and your make tool in \c examples/activeqt/simple. + + The \l{qaxserver-demo-simple.html}{demonstration} requires your + WebBrowser to support ActiveX controls, and scripting to be enabled. + + The simple ActiveX control is embedded using the \c <object> tag. + + \snippet doc/src/examples/activeqt/simple-demo.qdocinc 0 + + A simple HTML button is connected to the ActiveQt's about() slot. + + \snippet doc/src/examples/activeqt/simple-demo.qdocinc 1 + + A second ActiveX control - the standard Calendar Control - is instantiated + + \snippet doc/src/examples/activeqt/simple-demo.qdocinc 2 + + Events from the ActiveX controls are handled using both Visual Basic Script + and JavaScript. + + \snippet doc/src/examples/activeqt/simple-demo.qdocinc 3 +*/ diff --git a/doc/src/examples/webbrowser.qdoc b/doc/src/examples/webbrowser.qdoc new file mode 100644 index 0000000..ac9cec5 --- /dev/null +++ b/doc/src/examples/webbrowser.qdoc @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example activeqt/webbrowser + \title Web Browser Example (ActiveQt) + + The Web Browser example uses the Microsoft Web Browser + ActiveX control to implement a fully functional Web Browser + application. The user interface has been developed using the Qt + Designer integration of the QAxWidget class. + + The code demonstrates how the Qt application can communicate + with the embedded ActiveX controls using signals, slots and the + dynamicCall() function. + + \snippet examples/activeqt/webbrowser/main.cpp 0 + + The \c MainWindow class declares a \c QMainWindow based user interface, + using the \c Ui::MainWindow class generated by Qt Designer. A number + of slots are implemented to handle events from the various user + interface elements, including the \c WebBrowser object, which is a + QAxWidget hosting the Microsoft Web Browser control. + + \snippet examples/activeqt/webbrowser/main.cpp 1 + + The constructor initializes the user interface, installs a + progress bar on the status bar, and uses QAxBase::dynamicCall() + to invoke the \c GoHome() method of Internet Explorer to + navigate to the user's home page. + + \snippet examples/activeqt/webbrowser/main.cpp 2 + Different slots handle the signals emitted by the WebBrowser object. + + Connections that don't require any coding, i.e. connecting the \c back + action to the \c GoBack() slot, have already been made in Qt Designer. + + \snippet examples/activeqt/webbrowser/main.cpp 3 + \snippet examples/activeqt/webbrowser/main.cpp 4 + + The rest of the implementation is not related to ActiveQt - the actions + are handled by different slots, and the entry point function starts the + application using standard Qt APIs. + + To build the example you must first build the QAxContainer + library. Then run your make tool in \c + examples/activeqt/webbrowser and run the resulting \c + webbrowser.exe. +*/ diff --git a/doc/src/examples/wrapper-demo.qdocinc b/doc/src/examples/wrapper-demo.qdocinc new file mode 100644 index 0000000..a00c505 --- /dev/null +++ b/doc/src/examples/wrapper-demo.qdocinc @@ -0,0 +1,51 @@ +\raw HTML +//! [0] +<SCRIPT LANGUAGE="VBScript"> +Sub ToolButton_Clicked() + RadioButton.text = InputBox( "Enter something", "Wrapper Demo" ) +End Sub + +Sub PushButton_clicked() + MsgBox( "Thank you!" ) +End Sub + +Sub CheckBox_toggled( state ) + if state = 0 then + CheckBox.text = "Check me!" + else + CheckBox.text = "Uncheck me!" + end if +End Sub +</SCRIPT> +<p /> +A QPushButton:<br /> +<object ID="PushButton" CLASSID="CLSID:2B262458-A4B6-468B-B7D4-CF5FEE0A7092" +CODEBASE="http://qt.nokia.com/demos/wrapperax.cab"> + <PARAM NAME="text" VALUE="Click me!" /> +[Object not available! Did you forget to build and register the server?] +</object><br /> + +<p /> +A QCheckBox:<br /> +<object ID="CheckBox" CLASSID="CLSID:6E795de9-872d-43cf-a831-496ef9d86c68" +CODEBASE="http://qt.nokia.com/demos/wrapperax.cab"> + <PARAM NAME="text" VALUE="Check me!" /> +[Object not available! Did you forget to build and register the server?] +</object><br /> + +<p /> +A QToolButton:<br /> +<object ID="ToolButton" CLASSID="CLSID:7c0ffe7a-60c3-4666-bde2-5cf2b54390a1" +CODEBASE="http://qt.nokia.com/demos/wrapperax.cab"> +[Object not available! Did you forget to build and register the server?] +</object><br /> + +<p /> +A QRadioButton:<br /> +<object ID="RadioButton" CLASSID="CLSID:afcf78c8-446c-409a-93b3-ba2959039189" +CODEBASE="http://qt.nokia.com/demos/wrapperax.cab"> + <PARAM NAME="text" VALUE="Tune me!" /> +[Object not available! Did you forget to build and register the server?] +</object><br /> +//! [0] +\endraw diff --git a/doc/src/examples/wrapper.qdoc b/doc/src/examples/wrapper.qdoc new file mode 100644 index 0000000..980757c --- /dev/null +++ b/doc/src/examples/wrapper.qdoc @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qaxserver-demo-wrapper.html + + \title Standard Qt widgets in an HTML page + + \input examples/activeqt/wrapper-demo.qdocinc +*/ + +/*! + \example activeqt/wrapper + \title Wrapper Example (ActiveQt) + + The Wrapper example demonstrates how to export existing QWidget + classes as ActiveX controls, and the use of QAxFactory together + with the \c QAXFACTORY_EXPORT() macro. ActiveX controls in this + example are the standard button classes QPushButton, QCheckBox + and QRadioButton as provided by Qt. + + \snippet examples/activeqt/wrapper/main.cpp 0 + The factory implementation returns the list of supported controls, + creates controls on request and provides information about the unique + IDs of the COM classes and interfaces for each control. + + \snippet examples/activeqt/wrapper/main.cpp 1 + The factory is exported using the QAXFACTORY_EXPORT macro. + + To build the example you must first build the QAxServer library. + Then run \c qmake and your make tool in \c + examples/activeqt/wrapper. + + The \l{qaxserver-demo-wrapper.html}{demonstration} requires a + web browser that supports ActiveX controls, and scripting to be + enabled. + + \snippet examples/activeqt/wrapper-demo.qdocinc 0 +*/ diff --git a/doc/src/snippets/code/doc_src_examples_activeqt_comapp.qdoc b/doc/src/snippets/code/doc_src_examples_activeqt_comapp.qdoc new file mode 100644 index 0000000..40ee834 --- /dev/null +++ b/doc/src/snippets/code/doc_src_examples_activeqt_comapp.qdoc @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +Private Application As comappLib.Application +Private MyApp As Boolean + +Private Sub UpdateList() + DocumentList.Clear + DocumentsCount.Caption = Application.documents.Count + For Index = 0 To Application.documents.Count - 1 + DocumentList.AddItem (Application.documents.Item(Index).Title) + Next +End Sub + +Private Sub Form_Load() + On Error GoTo CreateNew + Set Application = GetObject(, "comapp.Application") + MyApp = False + GoTo Initialized +CreateNew: + On Error GoTo InitializeFailed + Set Application = New Application + Application.Visible = True + MyApp = True +Initialized: + Caption = Application.id + UpdateList +InitializeFailed: +End Sub + +Private Sub Form_Unload(Cancel As Integer) + If MyApp Then + Application.quit + End If +End Sub + +Private Sub NewDocument_Click() + Application.documents.addDocument + UpdateList +End Sub +//! [0] diff --git a/doc/src/snippets/code/doc_src_examples_activeqt_dotnet.qdoc b/doc/src/snippets/code/doc_src_examples_activeqt_dotnet.qdoc new file mode 100644 index 0000000..74c869e --- /dev/null +++ b/doc/src/snippets/code/doc_src_examples_activeqt_dotnet.qdoc @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +' VB is case insensitive, but our C++ controls are not. +' Me.resetButton.enabled = True +//! [0] diff --git a/doc/src/snippets/code/doc_src_examples_activeqt_menus.qdoc b/doc/src/snippets/code/doc_src_examples_activeqt_menus.qdoc new file mode 100644 index 0000000..a6f42aa --- /dev/null +++ b/doc/src/snippets/code/doc_src_examples_activeqt_menus.qdoc @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +<object ID="QMenus" CLASSID="CLSID:4dc3f340-a6f7-44e4-a79b-3e9217695fbd" +CODEBASE="http://qt.nokia.com/demos/menusax.cab"> +[Object not available! Did you forget to build and register the server?] +</object> +//! [0] diff --git a/doc/src/snippets/code/doc_src_qaxcontainer.pro b/doc/src/snippets/code/doc_src_qaxcontainer.pro new file mode 100644 index 0000000..ff39e67 --- /dev/null +++ b/doc/src/snippets/code/doc_src_qaxcontainer.pro @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#! [0] +CONFIG += qaxcontainer +#! [0] + + +#! [1] +TYPELIBS = file.tlb +#! [1] diff --git a/doc/src/snippets/code/doc_src_qaxserver.cpp b/doc/src/snippets/code/doc_src_qaxserver.cpp new file mode 100644 index 0000000..dc16776 --- /dev/null +++ b/doc/src/snippets/code/doc_src_qaxserver.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [3] +#include <QWidget> + +class MyActiveX : public QWidget +{ + Q_OBJECT +//! [3] + + +//! [4] +Q_CLASSINFO("ClassID", "{1D9928BD-4453-4bdd-903D-E525ED17FDE5}") +Q_CLASSINFO("InterfaceID", "{99F6860E-2C5A-42ec-87F2-43396F4BE389}") +Q_CLASSINFO("EventsID", "{0A3E9F27-E4F1-45bb-9E47-63099BCCD0E3}") +//! [4] + + +//! [5] +Q_PROPERTY(int value READ value WRITE setValue) +//! [5] + + +//! [6] +public: + MyActiveX(QWidget *parent = 0) + ... + + int value() const; + +public slots: + void setValue(int v); + ... + +signals: + void valueChange(int v); + ... + +}; +//! [6] + + +//! [7] +#include <QAxBindable> +#include <QWidget> + +class MyActiveX : public QWidget, public QAxBindable +{ + Q_OBJECT +//! [7] + + +//! [8] +QAXFACTORY_BEGIN("{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}", + "{a8f21901-7ff7-4f6a-b939-789620c03d83}") + QAXCLASS(MyWidget) + QAXCLASS(MyWidget2) + QAXTYPE(MySubType) +QAXFACTORY_END() +//! [8] + + +//! [9] +#include <QApplication> +#include <QAxFactory> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + if (!QAxFactory::isServer()) { + // create and show main window + } + return app.exec(); +} +//! [9] + + +//! [10] +MyFactory(const QUuid &, const QUuid &); +//! [10] + + +//! [11] +HMODULE dll = LoadLibrary("myserver.dll"); +typedef HRESULT(__stdcall *DllRegisterServerProc)(); +DllRegisterServerProc DllRegisterServer = + (DllRegisterServerProc)GetProcAddress(dll, "DllRegisterServer"); + +HRESULT res = E_FAIL; +if (DllRegisterServer) + res = DllRegisterServer(); +if (res != S_OK) + // error handling +//! [11] + + +//! [15] +class MyActiveX : public QWidget +{ + Q_OBJECT + Q_CLASSINFO("Version", "2.0") + Q_CLASSINFO("ClassID", "{7a4cffd8-cbcd-4ae9-ae7e-343e1e5710df}") + Q_CLASSINFO("InterfaceID", "{6fb035bf-8019-48d8-be51-ef05427d8994}") + Q_CLASSINFO("EventsID", "{c42fffdf-6557-47c9-817a-2da2228bc29c}") + Q_CLASSINFO("Insertable", "yes") + Q_CLASSINFO("ToSuperClass", "MyActiveX") + Q_PROPERTY(...) + +public: + MyActiveX(QWidget *parent = 0); + + ... +}; +//! [15] + + +//! [16] +class MyLicensedControl : public QWidget +{ + Q_OBJECT + Q_CLASSINFO("LicenseKey", "<key string>") + ... +}; +//! [16] + + +//! [17] +class AxImpl : public QAxAggregated, public ISomeCOMInterface +{ +public: + AxImpl() {} + + long queryInterface(const QUuid &iid, void **iface); + + // IUnknown + QAXAGG_IUNKNOWN + + // ISomeCOMInterface + ... +} +//! [17] + + +//! [18] +long AxImpl::queryInterface(const QUuid &iid, void **iface) +{ + *iface = 0; + if (iid == IID_ISomeCOMInterface) + *iface = (ISomeCOMInterface *)this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} +//! [18] + + +//! [19] +HRESULT AxImpl::QueryInterface(REFIID iid, void **iface) +{ + return controllingUnknown()->QueryInterface(iid, iface); +} +//! [19] + + +//! [20] +class MyActiveX : public QWidget, public QAxBindable +{ + Q_OBJECT + +public: + MyActiveX(QWidget *parent); + + QAxAggregated *createAggregate() + { + return new AxImpl(); + } +}; +//! [20] diff --git a/doc/src/snippets/code/doc_src_qaxserver.pro b/doc/src/snippets/code/doc_src_qaxserver.pro new file mode 100644 index 0000000..18d66f3 --- /dev/null +++ b/doc/src/snippets/code/doc_src_qaxserver.pro @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#! [0] +TEMPLATE = app +CONFIG += qaxserver + +RC_FILE = qaxserver.rc +... +#! [0] + + +#! [1] +TEMPLATE = lib +CONFIG += qaxserver dll + +DEF_FILE = qaxserver.def +RC_FILE = qaxserver.rc +... +#! [1] + + +#! [2] +TEMPLATE = lib +VERSION = 2.5 +... +#! [2] diff --git a/doc/src/snippets/code/doc_src_qaxserver.qdoc b/doc/src/snippets/code/doc_src_qaxserver.qdoc new file mode 100644 index 0000000..2fd79e3 --- /dev/null +++ b/doc/src/snippets/code/doc_src_qaxserver.qdoc @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [12] +cabarc N simpleax.cab simpleax.exe simple.inf +//! [12] + + +//! [13] +<object ID="MyActiveX1" CLASSID="CLSID:ad90301a-849e-4e8b-9a91-0a6dc5f6461f"> + ... +<\object> +//! [13] + + +//! [14] +<object ID=...> + <param name="name" value="value"> +<\object> +//! [14] diff --git a/doc/src/snippets/code/src_activeqt_container_qaxbase.cpp b/doc/src/snippets/code/src_activeqt_container_qaxbase.cpp new file mode 100644 index 0000000..5df221e --- /dev/null +++ b/doc/src/snippets/code/src_activeqt_container_qaxbase.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +connect(buttonBack, SIGNAL(clicked()), webBrowser, SLOT(GoBack())); +//! [0] + + +//! [1] +activeX->setProperty("text", "some text"); +int value = activeX->property("value"); +//! [1] + + +//! [2] +webBrowser->dynamicCall("GoHome()"); +//! [2] + + +//! [3] +connect(webBrowser, SIGNAL(TitleChanged(QString)), + this, SLOT(setCaption(QString))); +//! [3] + + +//! [4] +dispinterface IControl +{ +properties: + [id(1)] BSTR text; + [id(2)] IFontDisp *font; + +methods: + [id(6)] void showColumn([in] int i); + [id(3)] bool addColumn([in] BSTR t); + [id(4)] int fillList([in, out] SAFEARRAY(VARIANT) *list); + [id(5)] IDispatch *item([in] int i); +}; +//! [4] + + +//! [5] +QAxObject object("<CLSID>"); + +QString text = object.property("text").toString(); +object.setProperty("font", QFont("Times New Roman", 12)); + +connect(this, SIGNAL(clicked(int)), &object, SLOT(showColumn(int))); +bool ok = object.dynamicCall("addColumn(const QString&)", "Column 1").toBool(); + +QList<QVariant> varlist; +QList<QVariant> parameters; +parameters << QVariant(varlist); +int n = object.dynamicCall("fillList(QList<QVariant>&)", parameters).toInt(); + +QAxObject *item = object.querySubItem("item(int)", 5); +//! [5] + + +//! [6] +IUnknown *iface = 0; +activeX->queryInterface(IID_IUnknown, (void**)&iface); +if (iface) { + // use the interface + iface->Release(); +} +//! [6] + + +//! [7] +ctrl->setControl("{8E27C92B-1264-101C-8A2F-040224009C02}"); +//! [7] + + +//! [8] +ctrl->setControl("MSCal.Calendar"); +//! [8] + + +//! [9] +ctrl->setControl("Calendar Control 9.0"); +//! [9] + + +//! [10] +ctrl->setControl("c:/files/file.doc"); +//! [10] + + +//! [11] +<domain/username>:<password>@server/{8E27C92B-1264-101C-8A2F-040224009C02} +//! [11] + + +//! [12] +{8E27C92B-1264-101C-8A2F-040224009C02}:<LicenseKey> +//! [12] + + +//! [13] +{8E27C92B-1264-101C-8A2F-040224009C02}& +//! [13] + + +//! [14] +ctrl->setControl("DOMAIN/user:password@server/{8E27C92B-1264-101C-8A2F-040224009C02}:LicenseKey"); +//! [14] + + +//! [15] +activeX->dynamicCall("Navigate(const QString&)", "qt.nokia.com"); +//! [15] + + +//! [16] +activeX->dynamicCall("Navigate(\"qt.nokia.com\")"); +//! [16] + + +//! [17] +activeX->dynamicCall("Value", 5); +QString text = activeX->dynamicCall("Text").toString(); +//! [17] + + +//! [18] +IWebBrowser2 *webBrowser = 0; +activeX->queryInterface(IID_IWebBrowser2, (void **)&webBrowser); +if (webBrowser) { + webBrowser->Navigate2(pvarURL); + webBrowser->Release(); +} +//! [18] + + +//! [19] +QAxWidget outlook("Outlook.Application"); +QAxObject *session = outlook.querySubObject("Session"); +if (session) { + QAxObject *defFolder = session->querySubObject( + "GetDefaultFolder(OlDefaultFolders)", + "olFolderContacts"); + //... +} +//! [19] + + +//! [20] +void Receiver::slot(const QString &name, int argc, void *argv) +{ + VARIANTARG *params = (VARIANTARG*)argv; + if (name.startsWith("BeforeNavigate2(")) { + IDispatch *pDisp = params[argc-1].pdispVal; + VARIANTARG URL = *params[argc-2].pvarVal; + VARIANTARG Flags = *params[argc-3].pvarVal; + VARIANTARG TargetFrameName = *params[argc-4].pvarVal; + VARIANTARG PostData = *params[argc-5].pvarVal; + VARIANTARG Headers = *params[argc-6].pvarVal; + bool *Cancel = params[argc-7].pboolVal; + } +} +//! [20] diff --git a/doc/src/snippets/code/src_activeqt_container_qaxscript.cpp b/doc/src/snippets/code/src_activeqt_container_qaxscript.cpp new file mode 100644 index 0000000..ff911d1 --- /dev/null +++ b/doc/src/snippets/code/src_activeqt_container_qaxscript.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +function setNumber(number) +{ + n = number; +} +//! [0] + + +//! [1] +QValueList args; +args << 5; +script->call("setNumber(const QVariant&)", args); +//! [1] + + +//! [2] +script->call("setNumber(5)"); +//! [2] diff --git a/doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp b/doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp new file mode 100644 index 0000000..d3202ff --- /dev/null +++ b/doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +class MyActiveX : public QWidget, public QAxBindable +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue) + +public: + MyActiveX(QWidget *parent = 0); + ... + + int value() const; + void setValue(int); +}; +//! [0] + + +//! [1] +void MyActiveQt::setText(const QString &text) +{ + if (!requestPropertyChange("text")) + return; + + // update property + + propertyChanged("text"); +} +//! [1] + + +//! [2] +long AxImpl::queryInterface(const QUuid &iid, void **iface) +{ + *iface = 0; + if (iid == IID_ISomeCOMInterface) + *iface = (ISomeCOMInterface*)this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} +//! [2] + + +//! [3] +HRESULT AxImpl::QueryInterface(REFIID iid, void **iface) +{ + return controllingUnknown()->QueryInterface(iid, iface); +} + +ulong AxImpl::AddRef() +{ + return controllingUnknown()->AddRef(); +} + +ulong AxImpl::Release() +{ + return controllingUnknown()->Release(); +} +//! [3] diff --git a/doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp b/doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp new file mode 100644 index 0000000..6747f87 --- /dev/null +++ b/doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +QStringList ActiveQtFactory::featureList() const +{ + QStringList list; + list << "ActiveX1"; + list << "ActiveX2"; + return list; +} + +QObject *ActiveQtFactory::createObject(const QString &key) +{ + if (key == "ActiveX1") + return new ActiveX1(parent); + if (key == "ActiveX2") + return new ActiveX2(parent); + return 0; +} + +const QMetaObject *ActiveQtFactory::metaObject(const QString &key) const +{ + if (key == "ActiveX1") + return &ActiveX1::staticMetaObject; + if (key == "ActiveX2") + return &ActiveX2::staticMetaObject; +} + +QUuid ActiveQtFactory::classID(const QString &key) const +{ + if (key == "ActiveX1") + return "{01234567-89AB-CDEF-0123-456789ABCDEF}"; + ... + return QUuid(); +} + +QUuid ActiveQtFactory::interfaceID(const QString &key) const +{ + if (key == "ActiveX1") + return "{01234567-89AB-CDEF-0123-456789ABCDEF}"; + ... + return QUuid(); +} + +QUuid ActiveQtFactory::eventsID(const QString &key) const +{ + if (key == "ActiveX1") + return "{01234567-89AB-CDEF-0123-456789ABCDEF}"; + ... + return QUuid(); +} + +QAXFACTORY_EXPORT( + ActiveQtFactory, // factory class + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // type library ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}" // application ID +) +//! [0] + + +//! [1] +QAXFACTORY_BEGIN( + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // type library ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}" // application ID +) + QAXCLASS(Class1) + QAXCLASS(Class2) +QAXFACTORY_END() +//! [1] + + +//! [2] +#include <qapplication.h> +#include <qaxfactory.h> + +#include "theactivex.h" + +QAXFACTORY_DEFAULT( + TheActiveX, // widget class + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // class ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // interface ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // event interface ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // type library ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}" // application ID +) +//! [2] + + +//! [3] +settings->setValue("/CLSID/" + classID(key) + + "/Implemented Categories/" + + "/{00000000-0000-0000-000000000000}/.", + QString()); +//! [3] + + +//! [4] +settings->remove("/CLSID/" + classID(key) + + "/Implemented Categories" + + "/{00000000-0000-0000-000000000000}/."); +//! [4] + + +//! [5] +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + if (!QAxFactory::isServer()) { + // initialize for stand-alone execution + } + return app.exec(); +} +//! [5] + + +//! [6] +if (QAxFactory::isServer()) { + QAxFactory::stopServer(); + QAxFactory::startServer(QAxFactory::SingleInstance); +} +//! [6] + + +//! [7] +#include <qaxfactory.h> + +#include "theactivex.h" + +QAXFACTORY_DEFAULT( + TheActiveX, // widget class + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // class ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // interface ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // event interface ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // type library ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}" // application ID +) +//! [7] + + +//! [8] +QAXFACTORY_EXPORT( + MyFactory, // factory class + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // type library ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}" // application ID +) +//! [8] + + +//! [9] +QAXFACTORY_BEGIN( + "{01234567-89AB-CDEF-0123-456789ABCDEF}", // type library ID + "{01234567-89AB-CDEF-0123-456789ABCDEF}" // application ID +) + QAXCLASS(Class1) + QAXCLASS(Class2) +QAXFACTORY_END() +//! [9] diff --git a/examples/activeqt/README b/examples/activeqt/README new file mode 100644 index 0000000..24be2de --- /dev/null +++ b/examples/activeqt/README @@ -0,0 +1,39 @@ +Qt is supplied with a number of example applications and demonstrations that +have been written to provide developers with examples of the Qt API in use, +highlight good programming practice, and showcase features found in each of +Qt's core technologies. + +The example and demo launcher can be used to explore the different categories +available. It provides an overview of each example, lets you view the +documentation in Qt Assistant, and is able to launch examples and demos. + +Documentation for examples can be found in the Tutorial and Examples section +of the Qt documentation. + + +Finding the Qt Examples and Demos launcher +========================================== + +On Windows: + +The launcher can be accessed via the Windows Start menu. Select the menu +entry entitled "Qt Examples and Demos" entry in the submenu containing +the Qt tools. + +On Mac OS X: + +For the binary distribution, the qtdemo executable is installed in the +/Developer/Applications/Qt directory. For the source distribution, it is +installed alongside the other Qt tools on the path specified when Qt is +configured. + +On Unix/Linux: + +The qtdemo executable is installed alongside the other Qt tools on the path +specified when Qt is configured. + +On all platforms: + +The source code for the launcher can be found in the demos/qtdemo directory +in the Qt package. This example is built at the same time as the Qt libraries, +tools, examples, and demonstrations. diff --git a/examples/activeqt/activeqt.pro b/examples/activeqt/activeqt.pro new file mode 100644 index 0000000..79d257a --- /dev/null +++ b/examples/activeqt/activeqt.pro @@ -0,0 +1,20 @@ +TEMPLATE = subdirs +SUBDIRS += comapp \ + hierarchy \ + menus \ + multiple \ + simple \ + webbrowser \ + wrapper + +contains(QT_CONFIG, opengl):SUBDIRS += opengl + +# For now only the contain examples with mingw, for the others you need +# an IDL compiler +win32-g++*|wince*:SUBDIRS = webbrowser + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS activeqt.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt +INSTALLS += target sources diff --git a/examples/activeqt/comapp/comapp.pro b/examples/activeqt/comapp/comapp.pro new file mode 100644 index 0000000..84ce072 --- /dev/null +++ b/examples/activeqt/comapp/comapp.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG += qaxserver + +# Input +SOURCES += main.cpp + +RC_FILE = comapp.rc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/comapp +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS comapp.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/comapp +INSTALLS += target sources diff --git a/examples/activeqt/comapp/comapp.rc b/examples/activeqt/comapp/comapp.rc new file mode 100644 index 0000000..24e339a --- /dev/null +++ b/examples/activeqt/comapp/comapp.rc @@ -0,0 +1 @@ +1 TYPELIB "comapp.rc" diff --git a/examples/activeqt/comapp/main.cpp b/examples/activeqt/comapp/main.cpp new file mode 100644 index 0000000..66af248 --- /dev/null +++ b/examples/activeqt/comapp/main.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QAxFactory> +#include <QTabWidget> +#include <QTimer> + +class Application; +class DocumentList; + +//! [0] +class Document : public QObject +{ + Q_OBJECT + + Q_CLASSINFO("ClassID", "{2b5775cd-72c2-43da-bc3b-b0e8d1e1c4f7}") + Q_CLASSINFO("InterfaceID", "{2ce1761e-07a3-415c-bd11-0eab2c7283de}") + + Q_PROPERTY(Application *application READ application) + Q_PROPERTY(QString title READ title WRITE setTitle) + +public: + Document(DocumentList *list); + ~Document(); + + Application *application() const; + + QString title() const; + void setTitle(const QString &title); + +private: + QWidget *page; +}; +//! [0] + +//! [1] +class DocumentList : public QObject +{ + Q_OBJECT + + Q_CLASSINFO("ClassID", "{496b761d-924b-4554-a18a-8f3704d2a9a6}") + Q_CLASSINFO("InterfaceID", "{6c9e30e8-3ff6-4e6a-9edc-d219d074a148}") + + Q_PROPERTY(Application* application READ application) + Q_PROPERTY(int count READ count) + +public: + DocumentList(Application *application); + + int count() const; + Application *application() const; + +public slots: + Document *addDocument(); + Document *item(int index) const; + +private: + QList<Document*> list; +}; +//! [1] + +//! [2] +class Application : public QObject +{ + Q_OBJECT + + Q_CLASSINFO("ClassID", "{b50a71db-c4a7-4551-8d14-49983566afee}") + Q_CLASSINFO("InterfaceID", "{4a427759-16ef-4ed8-be79-59ffe5789042}") + Q_CLASSINFO("RegisterObject", "yes") + + Q_PROPERTY(DocumentList* documents READ documents) + Q_PROPERTY(QString id READ id) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible) + +public: + Application(QObject *parent = 0); + DocumentList *documents() const; + + QString id() const { return objectName(); } + + void setVisible(bool on); + bool isVisible() const; + + QTabWidget *window() const { return ui; } + +public slots: + void quit(); + +private: + DocumentList *docs; + + QTabWidget *ui; +}; +//! [2] + +//! [3] +Document::Document(DocumentList *list) +: QObject(list) +{ + QTabWidget *tabs = list->application()->window(); + page = new QWidget(tabs); + page->setWindowTitle("Unnamed"); + tabs->addTab(page, page->windowTitle()); + + page->show(); +} + +Document::~Document() +{ + delete page; +} + +Application *Document::application() const +{ + return qobject_cast<DocumentList*>(parent())->application(); +} + +QString Document::title() const +{ + return page->windowTitle(); +} + +void Document::setTitle(const QString &t) +{ + page->setWindowTitle(t); + + QTabWidget *tabs = application()->window(); + int index = tabs->indexOf(page); + tabs->setTabText(index, page->windowTitle()); +} + +//! [3] //! [4] +DocumentList::DocumentList(Application *application) +: QObject(application) +{ +} + +Application *DocumentList::application() const +{ + return qobject_cast<Application*>(parent()); +} + +int DocumentList::count() const +{ + return list.count(); +} + +Document *DocumentList::item(int index) const +{ + if (index >= list.count()) + return 0; + + return list.at(index); +} + +Document *DocumentList::addDocument() +{ + Document *document = new Document(this); + list.append(document); + + return document; +} + + +//! [4] //! [5] +Application::Application(QObject *parent) +: QObject(parent), ui(0) +{ + ui = new QTabWidget; + + setObjectName("From QAxFactory"); + docs = new DocumentList(this); +} + +DocumentList *Application::documents() const +{ + return docs; +} + +void Application::setVisible(bool on) +{ + ui->setShown(on); +} + +bool Application::isVisible() const +{ + return ui->isVisible(); +} + +void Application::quit() +{ + delete docs; + docs = 0; + + delete ui; + ui = 0; + QTimer::singleShot(0, qApp, SLOT(quit())); +} + +#include "main.moc" +//! [5] //! [6] + + +QAXFACTORY_BEGIN("{edd3e836-f537-4c6f-be7d-6014c155cc7a}", "{b7da3de8-83bb-4bbe-9ab7-99a05819e201}") + QAXCLASS(Application) + QAXTYPE(Document) + QAXTYPE(DocumentList) +QAXFACTORY_END() + +//! [6] //! [7] +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + app.setQuitOnLastWindowClosed(false); + + // started by COM - don't do anything + if (QAxFactory::isServer()) + return app.exec(); + + // started by user + Application appobject(0); + appobject.setObjectName("From Application"); + + QAxFactory::startServer(); + QAxFactory::registerActiveObject(&appobject); + + appobject.setVisible(true); + + QObject::connect(qApp, SIGNAL(lastWindowClosed()), &appobject, SLOT(quit())); + + return app.exec(); +} +//! [7] diff --git a/examples/activeqt/dotnet/walkthrough/Form1.cs b/examples/activeqt/dotnet/walkthrough/Form1.cs new file mode 100644 index 0000000..9fb572a --- /dev/null +++ b/examples/activeqt/dotnet/walkthrough/Form1.cs @@ -0,0 +1,127 @@ +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; + +namespace csharp +{ + /// <summary> + /// Summary description for Form1. + /// </summary> + public class Form1 : System.Windows.Forms.Form + { + private AxwrapperaxLib.AxQPushButton resetButton; + private AxmultipleaxLib.AxQAxWidget2 circleWidget; + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.Container components = null; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + + /// <summary> + /// Clean up any resources being used. + /// </summary> + protected override void Dispose( bool disposing ) + { + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1)); + this.resetButton = new AxwrapperaxLib.AxQPushButton(); + this.circleWidget = new AxmultipleaxLib.AxQAxWidget2(); + ((System.ComponentModel.ISupportInitialize)(this.resetButton)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.circleWidget)).BeginInit(); + this.SuspendLayout(); + // + // resetButton + // + this.resetButton.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right); + this.resetButton.Enabled = true; + this.resetButton.Location = new System.Drawing.Point(160, 296); + this.resetButton.Name = "resetButton"; + this.resetButton.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("resetButton.OcxState"))); + this.resetButton.Size = new System.Drawing.Size(168, 32); + this.resetButton.TabIndex = 1; + this.resetButton.clicked += new System.EventHandler(this.resetLineWidth); + // + // circleWidget + // + this.circleWidget.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right); + this.circleWidget.Enabled = true; + this.circleWidget.Location = new System.Drawing.Point(8, 8); + this.circleWidget.Name = "circleWidget"; + this.circleWidget.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("circleWidget.OcxState"))); + this.circleWidget.Size = new System.Drawing.Size(320, 264); + this.circleWidget.TabIndex = 2; + this.circleWidget.ClickEvent += new System.EventHandler(this.circleClicked); + // + // Form1 + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(336, 333); + this.Controls.AddRange(new System.Windows.Forms.Control[] { + this.circleWidget, + this.resetButton}); + this.Name = "Form1"; + this.Text = "Form1"; + ((System.ComponentModel.ISupportInitialize)(this.resetButton)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.circleWidget)).EndInit(); + this.ResumeLayout(false); + + } + #endregion + + /// <summary> + /// The main entry point for the application. + /// </summary> + [STAThread] + static void Main() + { + Application.Run(new Form1()); + } + +//! [0] + private void circleClicked(object sender, System.EventArgs e) + { + this.circleWidget.lineWidth++; + } +//! [0] + +//! [1] + private void resetLineWidth(object sender, System.EventArgs e) + { + this.circleWidget.lineWidth = 1; + this.resetButton.setFocus(); + } +//! [1] + } +} diff --git a/examples/activeqt/dotnet/walkthrough/Form1.resx b/examples/activeqt/dotnet/walkthrough/Form1.resx new file mode 100644 index 0000000..6353f82 --- /dev/null +++ b/examples/activeqt/dotnet/walkthrough/Form1.resx @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 1.3 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">1.3</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1">this is my long string</data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + [base64 mime encoded serialized .NET Framework object] + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + [base64 mime encoded string representing a byte array form of the .NET Framework object] + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>1.3</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="resetButton.OcxState" mimetype="application/x-microsoft.net.object.binary.base64"> + <value> + AAEAAAD/////AQAAAAAAAAAMAgAAAFpTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0xLjAuMzMw + MC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFT + eXN0ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAGwMA + AAIBAAAAAQAAAAAAAAAAAAAAAAYDAAAAAAAFAAAACGVuYWJsZWQAAAAAEgEAAAACeAAAAAAQAAAAAAAA + AAJ5AAAAABAAAAAAAAAABndpZHRoAAAAABAAAACoAAAAB2hlaWdodAAAAAAQAAAAGgAAAA1taW5pbXVt + V2lkdGgAAAAAEAAAAAAAAAAObWluaW11bUhlaWdodAAAAAAQAAAAAAAAAA1tYXhpbXVtV2lkdGgAAAAA + EAAAf/8AAAAObWF4aW11bUhlaWdodAAAAAAQAAB//wAAAA9iYWNrZ3JvdW5kTW9kZQAAAAAQAAAABAAA + ABdwYWxldHRlRm9yZWdyb3VuZENvbG9yAAAAAAr/AAAAAAAAF3BhbGV0dGVCYWNrZ3JvdW5kQ29sb3IA + AAAACv/U0MgAAAARYmFja2dyb3VuZE9yaWdpbgAAAAAQAAAAAAAAAAVmb250AAAAAAUAAAAYAE0AUwAg + AFMAaABlAGwAbAAgAEQAbABnAFP//wUBADIAAAAACGNhcHRpb24AAAAAA/////8AAAAJaWNvblRleHQA + AAAAA/////8AAAAObW91c2VUcmFja2luZwAAAAASAAAAAAxmb2N1c1BvbGljeQAAAAAQAAAAAQAAAA91 + cGRhdGVzRW5hYmxlZAAAAAASAQAAAAptYXhpbWl6ZWQAAAAAEgAAAAALZnVsbFNjcmVlbgAAAAASAAAA + AAxhY2NlcHREcm9wcwAAAAASAAAAABNpbnB1dE1ldGhvZEVuYWJsZWQAAAAAEgAAAAAFdGV4dAAAAAAD + AAAADAAmAFIAZQBzAGUAdAAAAAt0b2dnbGVUeXBlAAAAABAAAAAAAAAABWRvd24AAAAAEgAAAAAMdG9n + Z2xlU3RhdGUAAAAAEAAAAAAAAAALYXV0b1Jlc2l6ZQAAAAASAAAAAAthdXRvUmVwZWF0AAAAABIAAAAA + EGV4Y2x1c2l2ZVRvZ2dsZQAAAAASAAAAAAxhdXRvRGVmYXVsdAAAAAASAQAAAAttZW51QnV0dG9uAAAA + ABIAAAAABWZsYXQAAAAAEgAL +</value> + </data> + <data name="circleWidget.OcxState" mimetype="application/x-microsoft.net.object.binary.base64"> + <value> + AAEAAAD/////AQAAAAAAAAAMAgAAAFpTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0xLjAuMzMw + MC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFT + eXN0ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAALwAA + AAIBAAAAAQAAAAAAAAAAAAAAABoAAAAAAAAFAAAACmxpbmVXaWR0aAAAAAAQAAAAAAs= +</value> + </data> + <data name="$this.Name"> + <value>Form1</value> + </data> +</root>
\ No newline at end of file diff --git a/examples/activeqt/dotnet/walkthrough/Form1.vb b/examples/activeqt/dotnet/walkthrough/Form1.vb new file mode 100644 index 0000000..f5f241b --- /dev/null +++ b/examples/activeqt/dotnet/walkthrough/Form1.vb @@ -0,0 +1,88 @@ +Public Class Form1 + Inherits System.Windows.Forms.Form + +#Region " Windows Form Designer generated code " + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + 'Add any initialization after the InitializeComponent() call + + End Sub + + 'Form overrides dispose to clean up the component list. + Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) + If disposing Then + If Not (components Is Nothing) Then + components.Dispose() + End If + End If + MyBase.Dispose(disposing) + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + Friend WithEvents circleWidget As AxmultipleaxLib.AxQAxWidget2 + Friend WithEvents resetButton As AxwrapperaxLib.AxQPushButton + <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() + Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form1)) + Me.circleWidget = New AxmultipleaxLib.AxQAxWidget2() + Me.resetButton = New AxwrapperaxLib.AxQPushButton() + CType(Me.circleWidget, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.resetButton, System.ComponentModel.ISupportInitialize).BeginInit() + Me.SuspendLayout() + ' + 'circleWidget + ' + Me.circleWidget.Anchor = (((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ + Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right) + Me.circleWidget.Enabled = True + Me.circleWidget.Location = New System.Drawing.Point(8, 8) + Me.circleWidget.Name = "circleWidget" + Me.circleWidget.OcxState = CType(resources.GetObject("circleWidget.OcxState"), System.Windows.Forms.AxHost.State) + Me.circleWidget.Size = New System.Drawing.Size(280, 216) + Me.circleWidget.TabIndex = 0 + ' + 'resetButton + ' + Me.resetButton.Anchor = (System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right) + ' VB is case insensitive, but our C++ controls are not. + ' Me.resetButton.enabled = True + Me.resetButton.Location = New System.Drawing.Point(184, 240) + Me.resetButton.Name = "resetButton" + Me.resetButton.OcxState = CType(resources.GetObject("resetButton.OcxState"), System.Windows.Forms.AxHost.State) + Me.resetButton.Size = New System.Drawing.Size(104, 24) + Me.resetButton.TabIndex = 1 + ' + 'Form1 + ' + Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) + Me.ClientSize = New System.Drawing.Size(292, 273) + Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.resetButton, Me.circleWidget}) + Me.Name = "Form1" + Me.Text = "Form1" + CType(Me.circleWidget, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.resetButton, System.ComponentModel.ISupportInitialize).EndInit() + Me.ResumeLayout(False) + + End Sub + +#End Region + + Private Sub circleWidget_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles circleWidget.ClickEvent + Me.circleWidget.lineWidth = Me.circleWidget.lineWidth + 1 + End Sub + + Private Sub resetButton_clicked(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles resetButton.clicked + Me.circleWidget.lineWidth = 1 + Me.resetButton.setFocus() + End Sub +End Class diff --git a/examples/activeqt/dotnet/walkthrough/csharp.csproj b/examples/activeqt/dotnet/walkthrough/csharp.csproj new file mode 100644 index 0000000..4c5502b --- /dev/null +++ b/examples/activeqt/dotnet/walkthrough/csharp.csproj @@ -0,0 +1,143 @@ +<VisualStudioProject> + <CSHARP + ProjectType = "Local" + ProductVersion = "7.0.9466" + SchemaVersion = "1.0" + ProjectGuid = "{F15600FD-7677-4C01-B98A-6776CE500617}" + > + <Build> + <Settings + ApplicationIcon = "" + AssemblyKeyContainerName = "" + AssemblyName = "csharp" + AssemblyOriginatorKeyFile = "" + DefaultClientScript = "JScript" + DefaultHTMLPageLayout = "Grid" + DefaultTargetSchema = "IE50" + DelaySign = "false" + OutputType = "WinExe" + RootNamespace = "csharp" + StartupObject = "" + > + <Config + Name = "Debug" + AllowUnsafeBlocks = "false" + BaseAddress = "285212672" + CheckForOverflowUnderflow = "false" + ConfigurationOverrideFile = "" + DefineConstants = "DEBUG;TRACE" + DocumentationFile = "" + DebugSymbols = "true" + FileAlignment = "4096" + IncrementalBuild = "true" + Optimize = "false" + OutputPath = "bin\Debug\" + RegisterForComInterop = "false" + RemoveIntegerChecks = "false" + TreatWarningsAsErrors = "false" + WarningLevel = "4" + /> + <Config + Name = "Release" + AllowUnsafeBlocks = "false" + BaseAddress = "285212672" + CheckForOverflowUnderflow = "false" + ConfigurationOverrideFile = "" + DefineConstants = "TRACE" + DocumentationFile = "" + DebugSymbols = "false" + FileAlignment = "4096" + IncrementalBuild = "false" + Optimize = "true" + OutputPath = "bin\Release\" + RegisterForComInterop = "false" + RemoveIntegerChecks = "false" + TreatWarningsAsErrors = "false" + WarningLevel = "4" + /> + </Settings> + <References> + <Reference + Name = "System" + AssemblyName = "System" + HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll" + /> + <Reference + Name = "System.Data" + AssemblyName = "System.Data" + HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll" + /> + <Reference + Name = "System.Drawing" + AssemblyName = "System.Drawing" + HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll" + /> + <Reference + Name = "System.Windows.Forms" + AssemblyName = "System.Windows.Forms" + HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll" + /> + <Reference + Name = "System.XML" + AssemblyName = "System.Xml" + HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll" + /> + <Reference + Name = "stdole" + Guid = "{00020430-0000-0000-C000-000000000046}" + VersionMajor = "2" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "primary" + /> + <Reference + Name = "wrapperaxLib" + Guid = "{3B756301-0075-4E40-8BE8-5A81DE2426B7}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "tlbimp" + /> + <Reference + Name = "AxwrapperaxLib" + Guid = "{3B756301-0075-4E40-8BE8-5A81DE2426B7}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "aximp" + /> + <Reference + Name = "multipleaxLib" + Guid = "{05828915-AD1C-47AB-AB96-D6AD1E25F0E2}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "tlbimp" + /> + <Reference + Name = "AxmultipleaxLib" + Guid = "{05828915-AD1C-47AB-AB96-D6AD1E25F0E2}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "aximp" + /> + </References> + </Build> + <Files> + <Include> + <File + RelPath = "Form1.cs" + SubType = "Form" + BuildAction = "Compile" + /> + <File + RelPath = "Form1.resx" + DependentUpon = "Form1.cs" + BuildAction = "EmbeddedResource" + /> + </Include> + </Files> + </CSHARP> +</VisualStudioProject> + diff --git a/examples/activeqt/dotnet/walkthrough/vb.vbproj b/examples/activeqt/dotnet/walkthrough/vb.vbproj new file mode 100644 index 0000000..eb0a9d6 --- /dev/null +++ b/examples/activeqt/dotnet/walkthrough/vb.vbproj @@ -0,0 +1,147 @@ +<VisualStudioProject> + <VisualBasic + ProjectType = "Local" + ProductVersion = "7.0.9466" + SchemaVersion = "1.0" + ProjectGuid = "{BFF242A6-967C-4F73-BEBE-DED2D9C395C6}" + > + <Build> + <Settings + ApplicationIcon = "" + AssemblyKeyContainerName = "" + AssemblyName = "vb" + AssemblyOriginatorKeyFile = "" + AssemblyOriginatorKeyMode = "None" + DefaultClientScript = "JScript" + DefaultHTMLPageLayout = "Grid" + DefaultTargetSchema = "IE50" + DelaySign = "false" + OutputType = "WinExe" + OptionCompare = "Binary" + OptionExplicit = "On" + OptionStrict = "Off" + RootNamespace = "vb" + StartupObject = "vb.Form1" + > + <Config + Name = "Debug" + BaseAddress = "285212672" + ConfigurationOverrideFile = "" + DefineConstants = "" + DefineDebug = "true" + DefineTrace = "true" + DebugSymbols = "true" + IncrementalBuild = "true" + Optimize = "false" + OutputPath = "bin\" + RegisterForComInterop = "false" + RemoveIntegerChecks = "false" + TreatWarningsAsErrors = "false" + WarningLevel = "1" + /> + <Config + Name = "Release" + BaseAddress = "285212672" + ConfigurationOverrideFile = "" + DefineConstants = "" + DefineDebug = "false" + DefineTrace = "true" + DebugSymbols = "false" + IncrementalBuild = "false" + Optimize = "true" + OutputPath = "bin\" + RegisterForComInterop = "false" + RemoveIntegerChecks = "false" + TreatWarningsAsErrors = "false" + WarningLevel = "1" + /> + </Settings> + <References> + <Reference + Name = "System" + AssemblyName = "System" + /> + <Reference + Name = "System.Data" + AssemblyName = "System.Data" + /> + <Reference + Name = "System.Drawing" + AssemblyName = "System.Drawing" + /> + <Reference + Name = "System.Windows.Forms" + AssemblyName = "System.Windows.Forms" + /> + <Reference + Name = "System.XML" + AssemblyName = "System.Xml" + /> + <Reference + Name = "stdole" + Guid = "{00020430-0000-0000-C000-000000000046}" + VersionMajor = "2" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "primary" + /> + <Reference + Name = "wrapperaxLib" + Guid = "{3B756301-0075-4E40-8BE8-5A81DE2426B7}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "tlbimp" + /> + <Reference + Name = "multipleaxLib" + Guid = "{05828915-AD1C-47AB-AB96-D6AD1E25F0E2}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "tlbimp" + /> + <Reference + Name = "AxwrapperaxLib" + Guid = "{3B756301-0075-4E40-8BE8-5A81DE2426B7}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "aximp" + /> + <Reference + Name = "AxmultipleaxLib" + Guid = "{05828915-AD1C-47AB-AB96-D6AD1E25F0E2}" + VersionMajor = "1" + VersionMinor = "0" + Lcid = "0" + WrapperTool = "aximp" + /> + </References> + <Imports> + <Import Namespace = "Microsoft.VisualBasic" /> + <Import Namespace = "System" /> + <Import Namespace = "System.Collections" /> + <Import Namespace = "System.Data" /> + <Import Namespace = "System.Drawing" /> + <Import Namespace = "System.Diagnostics" /> + <Import Namespace = "System.Windows.Forms" /> + </Imports> + </Build> + <Files> + <Include> + <File + RelPath = "Form1.vb" + SubType = "Form" + BuildAction = "Compile" + /> + <File + RelPath = "Form1.resx" + DependentUpon = "Form1.vb" + BuildAction = "EmbeddedResource" + /> + </Include> + </Files> + </VisualBasic> +</VisualStudioProject> + diff --git a/examples/activeqt/dotnet/wrapper/app.csproj b/examples/activeqt/dotnet/wrapper/app.csproj new file mode 100644 index 0000000..dce4bf0 --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/app.csproj @@ -0,0 +1,93 @@ +<VisualStudioProject> + <CSHARP + ProjectType = "Local" + ProductVersion = "7.0.9466" + SchemaVersion = "1.0" + ProjectGuid = "{334C8F04-E034-4082-9380-43906DDE71AB}" + > + <Build> + <Settings + ApplicationIcon = "" + AssemblyKeyContainerName = "" + AssemblyName = "wrapper" + AssemblyOriginatorKeyFile = "" + DefaultClientScript = "JScript" + DefaultHTMLPageLayout = "Grid" + DefaultTargetSchema = "IE50" + DelaySign = "false" + OutputType = "Exe" + RootNamespace = "wrapper" + StartupObject = "" + > + <Config + Name = "Debug" + AllowUnsafeBlocks = "false" + BaseAddress = "285212672" + CheckForOverflowUnderflow = "false" + ConfigurationOverrideFile = "" + DefineConstants = "DEBUG;TRACE" + DocumentationFile = "" + DebugSymbols = "true" + FileAlignment = "4096" + IncrementalBuild = "true" + Optimize = "false" + OutputPath = "bin\Debug\" + RegisterForComInterop = "false" + RemoveIntegerChecks = "false" + TreatWarningsAsErrors = "false" + WarningLevel = "4" + /> + <Config + Name = "Release" + AllowUnsafeBlocks = "false" + BaseAddress = "285212672" + CheckForOverflowUnderflow = "false" + ConfigurationOverrideFile = "" + DefineConstants = "TRACE" + DocumentationFile = "" + DebugSymbols = "false" + FileAlignment = "4096" + IncrementalBuild = "false" + Optimize = "true" + OutputPath = "bin\Release\" + RegisterForComInterop = "false" + RemoveIntegerChecks = "false" + TreatWarningsAsErrors = "false" + WarningLevel = "4" + /> + </Settings> + <References> + <Reference + Name = "System" + AssemblyName = "System" + HintPath = "D:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll" + /> + <Reference + Name = "System.Data" + AssemblyName = "System.Data" + HintPath = "D:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll" + /> + <Reference + Name = "System.XML" + AssemblyName = "System.Xml" + HintPath = "D:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll" + /> + <Reference + Name = "lib" + AssemblyName = "lib" + HintPath = "lib\lib.dll" + /> + </References> + </Build> + <Files> + <Include> + <File + RelPath = "main.cs" + SubType = "Code" + BuildAction = "Compile" + /> + </Include> + </Files> + </CSHARP> +</VisualStudioProject> + diff --git a/examples/activeqt/dotnet/wrapper/lib/lib.vcproj b/examples/activeqt/dotnet/wrapper/lib/lib.vcproj new file mode 100644 index 0000000..f49c35d --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/lib/lib.vcproj @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding = "Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.00" + Name="lib" + ProjectGUID="{2E94A303-45A2-47AC-B87A-7C3519E9D6D8}" + Keyword="ManagedCProj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="2" + CharacterSet="2" + ManagedExtensions="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories=""$(QTDIR)\include";"$(QTDIR)\include\QtCore"" + PreprocessorDefinitions="WIN32;_DEBUG" + IgnoreStandardIncludePath="FALSE" + MinimalRebuild="FALSE" + BasicRuntimeChecks="0" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="QtCored4.lib" + OutputFile="lib.dll" + LinkIncremental="2" + AdditionalLibraryDirectories="$(QTDIR)/lib" + GenerateDebugInformation="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="2" + CharacterSet="2" + ManagedExtensions="TRUE"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories=""$(QTDIR)\include";"$(QTDIR)\include\QtCore"" + InlineFunctionExpansion="1" + PreprocessorDefinitions="WIN32;NDEBUG" + MinimalRebuild="FALSE" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="QtCore4.lib" + OutputFile="$(OutDir)/lib.dll" + LinkIncremental="1" + AdditionalLibraryDirectories="$(QTDIR)/lib" + GenerateDebugInformation="TRUE"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + </Configuration> + </Configurations> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"> + <File + RelativePath="networker.cpp"> + </File> + <File + RelativePath="tools.cpp"> + </File> + <File + RelativePath="worker.cpp"> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc"> + <File + RelativePath="networker.h"> + </File> + <File + RelativePath="tools.h"> + </File> + <File + RelativePath="worker.h"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCustomBuildTool" + CommandLine="$(QTDIR)\bin\moc.exe $(InputName).h -o moc_$(InputName).cpp" + Outputs="moc_$(InputName).cpp"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCustomBuildTool" + CommandLine="$(QTDIR)\bin\moc.exe $(InputName).h -o moc_$(InputName).cpp" + Outputs="moc_$(InputName).cpp"/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Generated MOC" + Filter=""> + <File + RelativePath="moc_worker.cpp"> + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/examples/activeqt/dotnet/wrapper/lib/networker.cpp b/examples/activeqt/dotnet/wrapper/lib/networker.cpp new file mode 100644 index 0000000..a40297b --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/lib/networker.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include "networker.h" +#include "worker.h" +#include "tools.h" + +netWorker::netWorker() +{ + workerObject = new Worker(); +} +//! [0] //! [1] + +netWorker::~netWorker() +{ + delete workerObject; +} +//! [1] //! [2] + +String *netWorker::get_StatusString() +{ + return QStringToString(workerObject->statusString()); +} +//! [2] //! [3] + +void netWorker::set_StatusString(String *string) +{ + workerObject->setStatusString(StringToQString(string)); + __raise statusStringChanged(string); +} +//! [3] diff --git a/examples/activeqt/dotnet/wrapper/lib/networker.h b/examples/activeqt/dotnet/wrapper/lib/networker.h new file mode 100644 index 0000000..ef61085 --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/lib/networker.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// lib.h + +#pragma once + +#using <mscorlib.dll> +using namespace System; + +//! [0] +class Worker; + +// .NET class +public __gc class netWorker +{ +public: + netWorker(); + ~netWorker(); + + __property String *get_StatusString(); + __property void set_StatusString(String *string); + + __event void statusStringChanged(String *args); + +private: + Worker *workerObject; +}; +//! [0] diff --git a/examples/activeqt/dotnet/wrapper/lib/tools.cpp b/examples/activeqt/dotnet/wrapper/lib/tools.cpp new file mode 100644 index 0000000..5a0fb20 --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/lib/tools.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include <QString> + +#using <mscorlib.dll> +#include <vcclr.h> + +using namespace System; + +String *QStringToString(const QString &qstring) +{ + return new String((const wchar_t *)qstring.utf16()); +} +//! [0] //! [1] + +QString StringToQString(String *string) +{ + const wchar_t __pin *chars = PtrToStringChars(string); + return QString::fromWCharArray(chars); +} +//! [1] diff --git a/examples/activeqt/dotnet/wrapper/lib/tools.h b/examples/activeqt/dotnet/wrapper/lib/tools.h new file mode 100644 index 0000000..96b9230 --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/lib/tools.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOOLS_H +#define TOOLS_H + +#using <mscorlib.dll> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +System::String *QStringToString(const QString &qstring); +QString StringToQString(System::String *string); + +#endif // TOOLS_H diff --git a/examples/activeqt/dotnet/wrapper/lib/worker.cpp b/examples/activeqt/dotnet/wrapper/lib/worker.cpp new file mode 100644 index 0000000..c55e85f --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/lib/worker.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "worker.h" +#include "tools.h" + +Worker::Worker() +{ + status = "Idle"; +} + +void Worker::setStatusString(const QString &string) +{ + status = string; + emit statusStringChanged(status); +} + +QString Worker::statusString() const +{ + return status; +} diff --git a/examples/activeqt/dotnet/wrapper/lib/worker.h b/examples/activeqt/dotnet/wrapper/lib/worker.h new file mode 100644 index 0000000..0b4b0e2 --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/lib/worker.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WORKER_H +#define WORKER_H + +#include <QObject> + +// native Qt/C++ class +//! [0] +class Worker : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString statusString READ statusString WRITE setStatusString) +public: + Worker(); + + QString statusString() const; + +public slots: + void setStatusString(const QString &string); + +signals: + void statusStringChanged(const QString &string); + +private: + QString status; +}; +//! [0] + +#endif // WORKER_H diff --git a/examples/activeqt/dotnet/wrapper/main.cs b/examples/activeqt/dotnet/wrapper/main.cs new file mode 100644 index 0000000..1d43029 --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/main.cs @@ -0,0 +1,40 @@ +//! [0] +using System; + +namespace WrapperApp +{ + class App + { + void Run() + { + netWorker worker = new netWorker(); + + worker.statusStringChanged += new netWorker.__Delegate_statusStringChanged(onStatusStringChanged); + + System.Console.Out.WriteLine(worker.StatusString); + + System.Console.Out.WriteLine("Working cycle begins..."); + worker.StatusString = "Working"; + worker.StatusString = "Lunch Break"; + worker.StatusString = "Working"; + worker.StatusString = "Idle"; + System.Console.Out.WriteLine("Working cycle ends..."); + } + + private void onStatusStringChanged(string str) + { + System.Console.Out.WriteLine(str); + } + + [STAThread] +//! [0] //! [1] + static void Main(string[] args) + { + App app = new App(); + app.Run(); + } +//! [1] //! [2] + } +//! [2] //! [3] +} +//! [3] diff --git a/examples/activeqt/dotnet/wrapper/wrapper.sln b/examples/activeqt/dotnet/wrapper/wrapper.sln new file mode 100644 index 0000000..e25e6bd --- /dev/null +++ b/examples/activeqt/dotnet/wrapper/wrapper.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app", "app.csproj", "{334C8F04-E034-4082-9380-43906DDE71AB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib", "lib\lib.vcproj", "{2E94A303-45A2-47AC-B87A-7C3519E9D6D8}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + {334C8F04-E034-4082-9380-43906DDE71AB}.0 = {2E94A303-45A2-47AC-B87A-7C3519E9D6D8} + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {334C8F04-E034-4082-9380-43906DDE71AB}.Debug.ActiveCfg = Debug|.NET + {334C8F04-E034-4082-9380-43906DDE71AB}.Debug.Build.0 = Debug|.NET + {334C8F04-E034-4082-9380-43906DDE71AB}.Release.ActiveCfg = Release|.NET + {334C8F04-E034-4082-9380-43906DDE71AB}.Release.Build.0 = Release|.NET + {2E94A303-45A2-47AC-B87A-7C3519E9D6D8}.Debug.ActiveCfg = Debug|Win32 + {2E94A303-45A2-47AC-B87A-7C3519E9D6D8}.Debug.Build.0 = Debug|Win32 + {2E94A303-45A2-47AC-B87A-7C3519E9D6D8}.Release.ActiveCfg = Release|Win32 + {2E94A303-45A2-47AC-B87A-7C3519E9D6D8}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/examples/activeqt/hierarchy/hierarchy.inf b/examples/activeqt/hierarchy/hierarchy.inf new file mode 100644 index 0000000..cb7e90f --- /dev/null +++ b/examples/activeqt/hierarchy/hierarchy.inf @@ -0,0 +1,9 @@ +[version] + signature="$CHICAGO$" + AdvancedINF=2.0 + [Add.Code] + hierarchyax.dll=hierarchyax.dll + [hierarchyax.dll] + file-win32-x86=thiscab + clsid={d574a747-8016-46db-a07c-b2b4854ee75c} + RegisterServer=yes diff --git a/examples/activeqt/hierarchy/hierarchy.pro b/examples/activeqt/hierarchy/hierarchy.pro new file mode 100644 index 0000000..abe5f1b --- /dev/null +++ b/examples/activeqt/hierarchy/hierarchy.pro @@ -0,0 +1,16 @@ +TEMPLATE = lib +TARGET = hierarchyax + +CONFIG += qt warn_off qaxserver dll +contains(CONFIG, static):DEFINES += QT_NODLL + +SOURCES = objects.cpp main.cpp +HEADERS = objects.h +RC_FILE = $$QT_SOURCE_TREE/src/activeqt/control/qaxserver.rc +DEF_FILE = $$QT_SOURCE_TREE/src/activeqt/control/qaxserver.def + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/hierarchy +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS hierarchy.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/hierarchy +INSTALLS += target sources diff --git a/examples/activeqt/hierarchy/main.cpp b/examples/activeqt/hierarchy/main.cpp new file mode 100644 index 0000000..0f23b71 --- /dev/null +++ b/examples/activeqt/hierarchy/main.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include "objects.h" +#include <QAxFactory> + +QAXFACTORY_BEGIN("{9e626211-be62-4d18-9483-9419358fbb03}", "{75c276de-1df5-451f-a004-e4fa1a587df1}") + QAXCLASS(QParentWidget) + QAXTYPE(QSubWidget) +QAXFACTORY_END() +//! [0] diff --git a/examples/activeqt/hierarchy/objects.cpp b/examples/activeqt/hierarchy/objects.cpp new file mode 100644 index 0000000..ab2cd61 --- /dev/null +++ b/examples/activeqt/hierarchy/objects.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "objects.h" +#include <QLayout> +#include <QPainter> + +/* Implementation of QParentWidget */ +//! [0] +QParentWidget::QParentWidget(QWidget *parent) +: QWidget(parent) +{ + vbox = new QVBoxLayout(this); +} + +//! [0] //! [1] +void QParentWidget::createSubWidget(const QString &name) +{ + QSubWidget *sw = new QSubWidget(this, name); + vbox->addWidget(sw); + sw->setLabel(name); + sw->show(); +} + +//! [1] //! [2] +QSubWidget *QParentWidget::subWidget(const QString &name) +{ + return findChild<QSubWidget*>(name); +} + +//! [2] +QSize QParentWidget::sizeHint() const +{ + return QWidget::sizeHint().expandedTo(QSize(100, 100)); +} + +/* Implementation of QSubWidget */ +//! [3] +QSubWidget::QSubWidget(QWidget *parent, const QString &name) +: QWidget(parent) +{ + setObjectName(name); +} + +void QSubWidget::setLabel(const QString &text) +{ + lbl = text; + setObjectName(text); + update(); +} + +QString QSubWidget::label() const +{ + return lbl; +} + +QSize QSubWidget::sizeHint() const +{ + QFontMetrics fm(font()); + return QSize(fm.width(lbl), fm.height()); +} + +void QSubWidget::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.setPen(palette().text().color()); + painter.drawText(rect(), Qt::AlignCenter, lbl); +//! [3] //! [4] +} +//! [4] diff --git a/examples/activeqt/hierarchy/objects.h b/examples/activeqt/hierarchy/objects.h new file mode 100644 index 0000000..f840a17 --- /dev/null +++ b/examples/activeqt/hierarchy/objects.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OBJECTS_H +#define OBJECTS_H + +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QVBoxLayout; +QT_END_NAMESPACE +class QSubWidget; + +//! [0] +class QParentWidget : public QWidget +{ + Q_OBJECT + Q_CLASSINFO("ClassID", "{d574a747-8016-46db-a07c-b2b4854ee75c}"); + Q_CLASSINFO("InterfaceID", "{4a30719d-d9c2-4659-9d16-67378209f822}"); + Q_CLASSINFO("EventsID", "{4a30719d-d9c2-4659-9d16-67378209f823}"); +public: + QParentWidget(QWidget *parent = 0); + + QSize sizeHint() const; + +public slots: + void createSubWidget( const QString &name ); + + QSubWidget *subWidget( const QString &name ); + +private: + QVBoxLayout *vbox; +}; +//! [0] + +//! [1] +class QSubWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY( QString label READ label WRITE setLabel ) + + Q_CLASSINFO("ClassID", "{850652f4-8f71-4f69-b745-bce241ccdc30}"); + Q_CLASSINFO("InterfaceID", "{2d76cc2f-3488-417a-83d6-debff88b3c3f}"); + Q_CLASSINFO("ToSuperClass", "QSubWidget"); + +public: + QSubWidget(QWidget *parent = 0, const QString &name = QString()); + + void setLabel( const QString &text ); + QString label() const; + + QSize sizeHint() const; + +protected: + void paintEvent( QPaintEvent *e ); + +private: + QString lbl; +}; +//! [1] + +#endif // OBJECTS_H diff --git a/examples/activeqt/menus/fileopen.xpm b/examples/activeqt/menus/fileopen.xpm new file mode 100644 index 0000000..880417e --- /dev/null +++ b/examples/activeqt/menus/fileopen.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *fileopen[] = { +" 16 13 5 1", +". c #040404", +"# c #808304", +"a c None", +"b c #f3f704", +"c c #f3f7f3", +"aaaaaaaaa...aaaa", +"aaaaaaaa.aaa.a.a", +"aaaaaaaaaaaaa..a", +"a...aaaaaaaa...a", +".bcb.......aaaaa", +".cbcbcbcbc.aaaaa", +".bcbcbcbcb.aaaaa", +".cbcb...........", +".bcb.#########.a", +".cb.#########.aa", +".b.#########.aaa", +"..#########.aaaa", +"...........aaaaa" +}; diff --git a/examples/activeqt/menus/filesave.xpm b/examples/activeqt/menus/filesave.xpm new file mode 100644 index 0000000..bd6870f --- /dev/null +++ b/examples/activeqt/menus/filesave.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *filesave[] = { +" 14 14 4 1", +". c #040404", +"# c #808304", +"a c #bfc2bf", +"b c None", +"..............", +".#.aaaaaaaa.a.", +".#.aaaaaaaa...", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".##........##.", +".############.", +".##.........#.", +".##......aa.#.", +".##......aa.#.", +".##......aa.#.", +"b............." +}; diff --git a/examples/activeqt/menus/main.cpp b/examples/activeqt/menus/main.cpp new file mode 100644 index 0000000..7d19e1f --- /dev/null +++ b/examples/activeqt/menus/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "menus.h" +#include <QApplication> +#include <QAxFactory> + +QAXFACTORY_DEFAULT(QMenus, + "{4dc3f340-a6f7-44e4-a79b-3e9217695fbd}", + "{9ee49617-7d5c-441a-b833-4b068d40d751}", + "{13eca64b-ee2a-4f3c-aa04-5d9d975979a7}", + "{ce947ee3-0403-4fdc-895a-4fe779394b46}", + "{8de435ce-8d2a-46ac-b3b3-cb800d0847c7}"); + +int main( int argc, char **argv ) +{ + QApplication a( argc, argv ); + + QWidget *window = 0; + if ( !QAxFactory::isServer() ) { + window = new QMenus(); + window->show(); + } + + return a.exec(); +} diff --git a/examples/activeqt/menus/menus.cpp b/examples/activeqt/menus/menus.cpp new file mode 100644 index 0000000..f1e8718 --- /dev/null +++ b/examples/activeqt/menus/menus.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "menus.h" +#include <QAction> +#include <QAxFactory> +#include <QMenuBar> +#include <QMessageBox> +#include <QTextEdit> +#include <QPixmap> + +#include "fileopen.xpm" +#include "filesave.xpm" + +QMenus::QMenus(QWidget *parent) + : QMainWindow(parent, 0) // QMainWindow's default flag is WType_TopLevel +{ + QAction *action; + + QMenu *file = new QMenu(this); + + action = new QAction(QPixmap((const char**)fileopen), "&Open", this); + action->setShortcut(tr("CTRL+O")); + connect(action, SIGNAL(triggered()), this, SLOT(fileOpen())); + file->addAction(action); + + action = new QAction(QPixmap((const char**)filesave),"&Save", this); + action->setShortcut(tr("CTRL+S")); + connect(action, SIGNAL(triggered()), this, SLOT(fileSave())); + file->addAction(action); + + QMenu *edit = new QMenu(this); + + action = new QAction("&Normal", this); + action->setShortcut(tr("CTRL+N")); + action->setToolTip("Normal"); + action->setStatusTip("Toggles Normal"); + action->setCheckable(true); + connect(action, SIGNAL(triggered()), this, SLOT(editNormal())); + edit->addAction(action); + + action = new QAction("&Bold", this); + action->setShortcut(tr("CTRL+B")); + action->setCheckable(true); + connect(action, SIGNAL(triggered()), this, SLOT(editBold())); + edit->addAction(action); + + action = new QAction("&Underline", this); + action->setShortcut(tr("CTRL+U")); + action->setCheckable(true); + connect(action, SIGNAL(triggered()), this, SLOT(editUnderline())); + edit->addAction(action); + + QMenu *advanced = new QMenu(this); + action = new QAction("&Font...", this); + connect(action, SIGNAL(triggered()), this, SLOT(editAdvancedFont())); + advanced->addAction(action); + + action = new QAction("&Style...", this); + connect(action, SIGNAL(triggered()), this, SLOT(editAdvancedStyle())); + advanced->addAction(action); + + edit->addMenu(advanced)->setText("&Advanced"); + + edit->addSeparator(); + + action = new QAction("Una&vailable", this); + action->setShortcut(tr("CTRL+V")); + action->setCheckable(true); + action->setEnabled(false); + connect(action, SIGNAL(triggered()), this, SLOT(editUnderline())); + edit->addAction(action); + + QMenu *help = new QMenu(this); + + action = new QAction("&About...", this); + action->setShortcut(tr("F1")); + connect(action, SIGNAL(triggered()), this, SLOT(helpAbout())); + help->addAction(action); + + action = new QAction("&About Qt...", this); + connect(action, SIGNAL(triggered()), this, SLOT(helpAboutQt())); + help->addAction(action); + + if (!QAxFactory::isServer()) + menuBar()->addMenu(file)->setText("&File"); + menuBar()->addMenu(edit)->setText("&Edit"); + menuBar()->addMenu(help)->setText("&Help"); + + editor = new QTextEdit(this); + setCentralWidget(editor); + + statusBar(); +} + +void QMenus::fileOpen() +{ + editor->append("File Open selected."); +} + +void QMenus::fileSave() +{ + editor->append("File Save selected."); +} + +void QMenus::editNormal() +{ + editor->append("Edit Normal selected."); +} + +void QMenus::editBold() +{ + editor->append("Edit Bold selected."); +} + +void QMenus::editUnderline() +{ + editor->append("Edit Underline selected."); +} + +void QMenus::editAdvancedFont() +{ + editor->append("Edit Advanced Font selected."); +} + +void QMenus::editAdvancedStyle() +{ + editor->append("Edit Advanced Style selected."); +} + +void QMenus::helpAbout() +{ + QMessageBox::about(this, "About QMenus", + "This example implements an in-place ActiveX control with menus and status messages."); +} + +void QMenus::helpAboutQt() +{ + QMessageBox::aboutQt(this); +} diff --git a/examples/activeqt/menus/menus.h b/examples/activeqt/menus/menus.h new file mode 100644 index 0000000..55aa995 --- /dev/null +++ b/examples/activeqt/menus/menus.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MENUS_H +#define MENUS_H + +#include <QMainWindow> + +QT_BEGIN_NAMESPACE +class QTextEdit; +QT_END_NAMESPACE + +class QMenus : public QMainWindow +{ + Q_OBJECT + +public: + QMenus(QWidget *parent = 0); + +public slots: + void fileOpen(); + void fileSave(); + + void editNormal(); + void editBold(); + void editUnderline(); + + void editAdvancedFont(); + void editAdvancedStyle(); + + void helpAbout(); + void helpAboutQt(); + +private: + QTextEdit *editor; +}; + +#endif // MENUS_H diff --git a/examples/activeqt/menus/menus.inf b/examples/activeqt/menus/menus.inf new file mode 100644 index 0000000..f97efe8 --- /dev/null +++ b/examples/activeqt/menus/menus.inf @@ -0,0 +1,9 @@ +[version] + signature="$CHICAGO$" + AdvancedINF=2.0 + [Add.Code] + menusax.exe=menusax.exe + [menusax.exe] + file-win32-x86=thiscab + clsid={4dc3f340-a6f7-44e4-a79b-3e9217695fbd} + RegisterServer=yes diff --git a/examples/activeqt/menus/menus.pro b/examples/activeqt/menus/menus.pro new file mode 100644 index 0000000..c962b6b --- /dev/null +++ b/examples/activeqt/menus/menus.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +TARGET = menusax + +CONFIG += qt warn_off qaxserver + +SOURCES = main.cpp menus.cpp +HEADERS = menus.h +RC_FILE = $$QT_SOURCE_TREE/src/activeqt/control/qaxserver.rc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/menus +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS menus.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/menus +INSTALLS += target sources diff --git a/examples/activeqt/multiple/ax1.h b/examples/activeqt/multiple/ax1.h new file mode 100644 index 0000000..79c5109 --- /dev/null +++ b/examples/activeqt/multiple/ax1.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AX1_H +#define AX1_H + +#include <QWidget> +#include <QPainter> + +//! [0] +class QAxWidget1 : public QWidget +{ + Q_OBJECT + Q_CLASSINFO("ClassID", "{1D9928BD-4453-4bdd-903D-E525ED17FDE5}") + Q_CLASSINFO("InterfaceID", "{99F6860E-2C5A-42ec-87F2-43396F4BE389}") + Q_CLASSINFO("EventsID", "{0A3E9F27-E4F1-45bb-9E47-63099BCCD0E3}") + + Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor) +public: + QAxWidget1(QWidget *parent = 0) + : QWidget(parent), fill_color(Qt::red) + { + } + + QColor fillColor() const + { + return fill_color; + } + void setFillColor(const QColor &fc) + { + fill_color = fc; + repaint(); + } + +protected: + void paintEvent(QPaintEvent *e) + { + QPainter paint(this); + QRect r = rect(); + r.adjust(10, 10, -10, -10); + paint.fillRect(r, fill_color); + } + +private: + QColor fill_color; +}; +//! [0] + +#endif // AX1_H diff --git a/examples/activeqt/multiple/ax2.h b/examples/activeqt/multiple/ax2.h new file mode 100644 index 0000000..3069bcf --- /dev/null +++ b/examples/activeqt/multiple/ax2.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AX2_H +#define AX2_H + +#include <QWidget> +#include <QPainter> + +//! [0] +class QAxWidget2 : public QWidget +{ + Q_OBJECT + Q_CLASSINFO("ClassID", "{58139D56-6BE9-4b17-937D-1B1EDEDD5B71}") + Q_CLASSINFO("InterfaceID", "{B66280AB-08CC-4dcc-924F-58E6D7975B7D}") + Q_CLASSINFO("EventsID", "{D72BACBA-03C4-4480-B4BB-DE4FE3AA14A0}") + Q_CLASSINFO("ToSuperClass", "QAxWidget2") + Q_CLASSINFO("StockEvents", "yes") + Q_CLASSINFO("Insertable", "yes") + + Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth ) +public: + QAxWidget2(QWidget *parent = 0) + : QWidget(parent), line_width( 1 ) + { + } + + int lineWidth() const + { + return line_width; + } + void setLineWidth( int lw ) + { + line_width = lw; + repaint(); + } + +protected: + void paintEvent( QPaintEvent *e ) + { + QPainter paint( this ); + QPen pen = paint.pen(); + pen.setWidth( line_width ); + paint.setPen( pen ); + + QRect r = rect(); + r.adjust( 10, 10, -10, -10 ); + paint.drawEllipse( r ); + } + +private: + int line_width; +}; +//! [0] + +#endif // AX2_H diff --git a/examples/activeqt/multiple/main.cpp b/examples/activeqt/multiple/main.cpp new file mode 100644 index 0000000..d7ecdc6 --- /dev/null +++ b/examples/activeqt/multiple/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include "ax1.h" +#include "ax2.h" +#include <QAxFactory> + +QT_USE_NAMESPACE + +QAXFACTORY_BEGIN("{98DE28B6-6CD3-4e08-B9FA-3D1DB43F1D2F}", "{05828915-AD1C-47ab-AB96-D6AD1E25F0E2}") + QAXCLASS(QAxWidget1) + QAXCLASS(QAxWidget2) +QAXFACTORY_END() +//! [0] diff --git a/examples/activeqt/multiple/multiple.inf b/examples/activeqt/multiple/multiple.inf new file mode 100644 index 0000000..7f6be76 --- /dev/null +++ b/examples/activeqt/multiple/multiple.inf @@ -0,0 +1,9 @@ +[version] + signature="$CHICAGO$" + AdvancedINF=2.0 + [Add.Code] + multipleax.dll=multipleax.dll + [multipleax.dll] + file-win32-x86=thiscab + clsid={1D9928BD-4453-4bdd-903D-E525ED17FDE5} + RegisterServer=yes diff --git a/examples/activeqt/multiple/multiple.pro b/examples/activeqt/multiple/multiple.pro new file mode 100644 index 0000000..7b86950 --- /dev/null +++ b/examples/activeqt/multiple/multiple.pro @@ -0,0 +1,16 @@ +TEMPLATE = lib +TARGET = multipleax + +CONFIG += qt warn_off qaxserver dll +contains(CONFIG, static):DEFINES += QT_NODLL + +SOURCES = main.cpp +HEADERS = ax1.h ax2.h +RC_FILE = multipleax.rc +DEF_FILE = $$QT_SOURCE_TREE/src/activeqt/control/qaxserver.def + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/multiple +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS multiple.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/multiple +INSTALLS += target sources diff --git a/examples/activeqt/multiple/multipleax.rc b/examples/activeqt/multiple/multipleax.rc new file mode 100644 index 0000000..b16b3a9 --- /dev/null +++ b/examples/activeqt/multiple/multipleax.rc @@ -0,0 +1,32 @@ +#include "winver.h" + +1 TYPELIB "multipleax.rc" +1 ICON DISCARDABLE "..\\..\\..\\src\\activeqt\\control\\qaxserver.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL + FILEOS 0x00040000L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Multiple Example (ActiveQt)" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "multipleax.dll" + VALUE "OriginalFilename", "multipleax.dll" + VALUE "ProductName", "Multiple Example (ActiveQt)" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/examples/activeqt/opengl/glbox.cpp b/examples/activeqt/opengl/glbox.cpp new file mode 100644 index 0000000..bf16232 --- /dev/null +++ b/examples/activeqt/opengl/glbox.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** This is a simple QGLWidget displaying an openGL wireframe box +** +** The OpenGL code is mostly borrowed from Brian Pauls "spin" example +** in the Mesa distribution +** +****************************************************************************/ + +#include "glbox.h" +#include <QAxAggregated> +#include <QUuid> +//! [0] +#include <objsafe.h> +//! [0] + +#if defined(Q_CC_MSVC) +#pragma warning(disable:4305) // init: truncation from const double to float +#endif + +/*! + Create a GLBox widget +*/ + +GLBox::GLBox( QWidget* parent, const char* name ) + : QGLWidget( parent ) +{ + xRot = yRot = zRot = 0.0; // default object rotation + scale = 1.25; // default object scale + object = 0; +} + + +/*! + Release allocated resources +*/ + +GLBox::~GLBox() +{ + makeCurrent(); + glDeleteLists( object, 1 ); +} + + +/*! + Paint the box. The actual openGL commands for drawing the box are + performed here. +*/ + +void GLBox::paintGL() +{ + glClear( GL_COLOR_BUFFER_BIT ); + + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -10.0 ); + glScalef( scale, scale, scale ); + + glRotatef( xRot, 1.0, 0.0, 0.0 ); + glRotatef( yRot, 0.0, 1.0, 0.0 ); + glRotatef( zRot, 0.0, 0.0, 1.0 ); + + glCallList( object ); +} + + +/*! + Set up the OpenGL rendering state, and define display list +*/ + +void GLBox::initializeGL() +{ + qglClearColor(Qt::black); // Let OpenGL clear to black + object = makeObject(); // Generate an OpenGL display list + glShadeModel( GL_FLAT ); +} + + + +/*! + Set up the OpenGL view port, matrix mode, etc. +*/ + +void GLBox::resizeGL( int w, int h ) +{ + glViewport( 0, 0, (GLint)w, (GLint)h ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 ); + glMatrixMode( GL_MODELVIEW ); +} + + +/*! + Generate an OpenGL display list for the object to be shown, i.e. the box +*/ + +GLuint GLBox::makeObject() +{ + GLuint list; + + list = glGenLists( 1 ); + + glNewList( list, GL_COMPILE ); + + qglColor(Qt::white); // Shorthand for glColor3f or glIndex + + glLineWidth( 2.0 ); + + glBegin( GL_LINE_LOOP ); + glVertex3f( 1.0, 0.5, -0.4 ); + glVertex3f( 1.0, -0.5, -0.4 ); + glVertex3f( -1.0, -0.5, -0.4 ); + glVertex3f( -1.0, 0.5, -0.4 ); + glEnd(); + + glBegin( GL_LINE_LOOP ); + glVertex3f( 1.0, 0.5, 0.4 ); + glVertex3f( 1.0, -0.5, 0.4 ); + glVertex3f( -1.0, -0.5, 0.4 ); + glVertex3f( -1.0, 0.5, 0.4 ); + glEnd(); + + glBegin( GL_LINES ); + glVertex3f( 1.0, 0.5, -0.4 ); glVertex3f( 1.0, 0.5, 0.4 ); + glVertex3f( 1.0, -0.5, -0.4 ); glVertex3f( 1.0, -0.5, 0.4 ); + glVertex3f( -1.0, -0.5, -0.4 ); glVertex3f( -1.0, -0.5, 0.4 ); + glVertex3f( -1.0, 0.5, -0.4 ); glVertex3f( -1.0, 0.5, 0.4 ); + glEnd(); + + glEndList(); + + return list; +} + + +/*! + Set the rotation angle of the object to \e degrees around the X axis. +*/ + +void GLBox::setXRotation( int degrees ) +{ + xRot = (GLfloat)(degrees % 360); + updateGL(); +} + + +/*! + Set the rotation angle of the object to \e degrees around the Y axis. +*/ + +void GLBox::setYRotation( int degrees ) +{ + yRot = (GLfloat)(degrees % 360); + updateGL(); +} + + +/*! + Set the rotation angle of the object to \e degrees around the Z axis. +*/ + +void GLBox::setZRotation( int degrees ) +{ + zRot = (GLfloat)(degrees % 360); + updateGL(); +} + +//! [1] +class ObjectSafetyImpl : public QAxAggregated, + public IObjectSafety +{ +public: +//! [1] //! [2] + ObjectSafetyImpl() {} + + long queryInterface( const QUuid &iid, void **iface ) + { + *iface = 0; + if ( iid == IID_IObjectSafety ) + *iface = (IObjectSafety*)this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; + } + +//! [2] //! [3] + QAXAGG_IUNKNOWN; + +//! [3] //! [4] + HRESULT WINAPI GetInterfaceSafetyOptions( REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions ) + { + *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACESAFE_FOR_UNTRUSTED_CALLER; + *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACESAFE_FOR_UNTRUSTED_CALLER; + return S_OK; + } + HRESULT WINAPI SetInterfaceSafetyOptions( REFIID riid, DWORD pdwSupportedOptions, DWORD pdwEnabledOptions ) + { + return S_OK; + } +}; +//! [4] //! [5] + +QAxAggregated *GLBox::createAggregate() +{ + return new ObjectSafetyImpl(); +} +//! [5] diff --git a/examples/activeqt/opengl/glbox.h b/examples/activeqt/opengl/glbox.h new file mode 100644 index 0000000..e4740fc --- /dev/null +++ b/examples/activeqt/opengl/glbox.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** This is a simple QGLWidget displaying an openGL wireframe box +** +****************************************************************************/ + +#ifndef GLBOX_H +#define GLBOX_H + +#include <QtOpenGL> +//! [0] +#include <QAxBindable> + +class GLBox : public QGLWidget, + public QAxBindable +{ + Q_OBJECT +//! [0] //! [1] + +public: + + GLBox( QWidget* parent, const char* name = 0 ); + ~GLBox(); + + QAxAggregated *createAggregate(); + +public slots: + + void setXRotation( int degrees ); +//! [1] + void setYRotation( int degrees ); + void setZRotation( int degrees ); + +protected: + + void initializeGL(); + void paintGL(); + void resizeGL( int w, int h ); + + virtual GLuint makeObject(); + +private: + + GLuint object; + GLfloat xRot, yRot, zRot, scale; + +}; + +#endif // GLBOX_H diff --git a/examples/activeqt/opengl/globjwin.cpp b/examples/activeqt/opengl/globjwin.cpp new file mode 100644 index 0000000..2626125 --- /dev/null +++ b/examples/activeqt/opengl/globjwin.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "globjwin.h" +#include "glbox.h" +#include <QPushButton> +#include <QSlider> +#include <QLayout> +#include <QFrame> +#include <QMenuBar> +#include <QMenu> +#include <QApplication> + + +GLObjectWindow::GLObjectWindow(QWidget* parent) + : QWidget(parent) +{ + + // Create a menu + QMenu *file = new QMenu( this ); + file->addAction( "Exit", qApp, SLOT(quit())/*, CTRL+Key_Q*/); + + // Create a menu bar + QMenuBar *m = new QMenuBar( this ); + m->addMenu(file)->setText("&File"); + + // Create a nice frame to put around the OpenGL widget + QFrame* f = new QFrame(this); + f->setFrameStyle( QFrame::Sunken | QFrame::Panel ); + f->setLineWidth( 2 ); + + // Create our OpenGL widget + GLBox* c = new GLBox( f, "glbox"); + + // Create the three sliders; one for each rotation axis + QSlider* x = new QSlider(Qt::Vertical, this); + x->setMaximum(360); + x->setPageStep(60); + x->setTickPosition( QSlider::TicksLeft ); + QObject::connect( x, SIGNAL(valueChanged(int)),c,SLOT(setXRotation(int)) ); + + QSlider* y = new QSlider(Qt::Vertical, this); + y->setMaximum(360); + y->setPageStep(60); + y->setTickPosition( QSlider::TicksLeft ); + QObject::connect( y, SIGNAL(valueChanged(int)),c,SLOT(setYRotation(int)) ); + + QSlider* z = new QSlider(Qt::Vertical, this); + z->setMaximum(360); + z->setPageStep(60); + z->setTickPosition( QSlider::TicksLeft ); + QObject::connect( z, SIGNAL(valueChanged(int)),c,SLOT(setZRotation(int)) ); + + // Now that we have all the widgets, put them into a nice layout + + // Top level layout, puts the sliders to the left of the frame/GL widget + QHBoxLayout* hlayout = new QHBoxLayout(this); + + // Put the sliders on top of each other + QVBoxLayout* vlayout = new QVBoxLayout(); + vlayout->addWidget( x ); + vlayout->addWidget( y ); + vlayout->addWidget( z ); + + // Put the GL widget inside the frame + QHBoxLayout* flayout = new QHBoxLayout(f); + flayout->setMargin(0); + flayout->addWidget( c, 1 ); + + hlayout->setMenuBar( m ); + hlayout->addLayout( vlayout ); + hlayout->addWidget( f, 1 ); +} diff --git a/examples/activeqt/opengl/globjwin.h b/examples/activeqt/opengl/globjwin.h new file mode 100644 index 0000000..5f660af --- /dev/null +++ b/examples/activeqt/opengl/globjwin.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** The GLObjectWindow contains a GLBox and three sliders connected to +** the GLBox's rotation slots. +** +****************************************************************************/ + +#ifndef GLOBJWIN_H +#define GLOBJWIN_H + +#include <qwidget.h> + +class GLObjectWindow : public QWidget +{ + Q_OBJECT + +public: + GLObjectWindow(QWidget *parent = 0); +}; + +#endif diff --git a/examples/activeqt/opengl/main.cpp b/examples/activeqt/opengl/main.cpp new file mode 100644 index 0000000..4a16bac --- /dev/null +++ b/examples/activeqt/opengl/main.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ +// +// Qt OpenGL example: Box +// +// A small example showing how a GLWidget can be used just as any Qt widget +// +// File: main.cpp +// +// The main() function +// + +#include "globjwin.h" +#include "glbox.h" +#include <QApplication> +#include <QtOpenGL> +//! [0] +#include <QAxFactory> + +QAXFACTORY_DEFAULT( GLBox, + "{5fd9c22e-ed45-43fa-ba13-1530bb6b03e0}", + "{33b051af-bb25-47cf-a390-5cfd2987d26a}", + "{8c996c29-eafa-46ac-a6f9-901951e765b5}", + "{2c3c183a-eeda-41a4-896e-3d9c12c3577d}", + "{83e16271-6480-45d5-aaf1-3f40b7661ae4}" + ) + +//! [0] //! [1] +/* + The main program is here. +*/ + +int main( int argc, char **argv ) +{ + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication a(argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + qWarning( "This system has no OpenGL support. Exiting." ); + return -1; + } + + if ( !QAxFactory::isServer() ) { + GLObjectWindow w; + w.resize( 400, 350 ); + w.show(); + return a.exec(); +//! [1] //! [2] + } + return a.exec(); +//! [2] //! [3] +} +//! [3] diff --git a/examples/activeqt/opengl/opengl.inf b/examples/activeqt/opengl/opengl.inf new file mode 100644 index 0000000..4a79e67 --- /dev/null +++ b/examples/activeqt/opengl/opengl.inf @@ -0,0 +1,9 @@ +[version] + signature="$CHICAGO$" + AdvancedINF=2.0 + [Add.Code] + openglax.exe=openglax.exe + [openglax.exe] + file-win32-x86=thiscab + clsid={5fd9c22e-ed45-43fa-ba13-1530bb6b03e0} + RegisterServer=yes diff --git a/examples/activeqt/opengl/opengl.pro b/examples/activeqt/opengl/opengl.pro new file mode 100644 index 0000000..8eb81be --- /dev/null +++ b/examples/activeqt/opengl/opengl.pro @@ -0,0 +1,19 @@ +TEMPLATE = app +TARGET = openglax + +CONFIG += qt warn_off qaxserver + +QT += opengl + +HEADERS = glbox.h \ + globjwin.h +SOURCES = glbox.cpp \ + globjwin.cpp \ + main.cpp +RC_FILE = $$QT_SOURCE_TREE/src/activeqt/control/qaxserver.rc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/opengl +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS opengl.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/opengl +INSTALLS += target sources diff --git a/examples/activeqt/qutlook/addressview.cpp b/examples/activeqt/qutlook/addressview.cpp new file mode 100644 index 0000000..45ce662 --- /dev/null +++ b/examples/activeqt/qutlook/addressview.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include "addressview.h" +#include "msoutl.h" +#include <QtGui> + +class AddressBookModel : public QAbstractListModel +{ +public: + AddressBookModel(AddressView *parent); + ~AddressBookModel(); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role) const; + + void changeItem(const QModelIndex &index, const QString &firstName, const QString &lastName, const QString &address, const QString &email); + void addItem(const QString &firstName, const QString &lastName, const QString &address, const QString &email); + void update(); + +private: + Outlook::Application outlook; + Outlook::Items * contactItems; + + mutable QHash<QModelIndex, QStringList> cache; +}; +//! [0] //! [1] + +AddressBookModel::AddressBookModel(AddressView *parent) +: QAbstractListModel(parent) +{ + if (!outlook.isNull()) { + Outlook::NameSpace session(outlook.Session()); + session.Logon(); + Outlook::MAPIFolder *folder = session.GetDefaultFolder(Outlook::olFolderContacts); + contactItems = new Outlook::Items(folder->Items()); + connect(contactItems, SIGNAL(ItemAdd(IDispatch*)), parent, SLOT(updateOutlook())); + connect(contactItems, SIGNAL(ItemChange(IDispatch*)), parent, SLOT(updateOutlook())); + connect(contactItems, SIGNAL(ItemRemove()), parent, SLOT(updateOutlook())); + + delete folder; + } +} + +//! [1] //! [2] +AddressBookModel::~AddressBookModel() +{ + delete contactItems; + + if (!outlook.isNull()) + Outlook::NameSpace(outlook.Session()).Logoff(); +} + +//! [2] //! [3] +int AddressBookModel::rowCount(const QModelIndex &) const +{ + return contactItems ? contactItems->Count() : 0; +} + +int AddressBookModel::columnCount(const QModelIndex &parent) const +{ + return 4; +} + +//! [3] //! [4] +QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + switch (section) { + case 0: + return tr("First Name"); + case 1: + return tr("Last Name"); + case 2: + return tr("Address"); + case 3: + return tr("Email"); + default: + break; + } + + return QVariant(); +} + +//! [4] //! [5] +QVariant AddressBookModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || role != Qt::DisplayRole) + return QVariant(); + + QStringList data; + if (cache.contains(index)) { + data = cache.value(index); + } else { + Outlook::ContactItem contact(contactItems->Item(index.row() + 1)); + data << contact.FirstName() << contact.LastName() << contact.HomeAddress() << contact.Email1Address(); + cache.insert(index, data); + } + + if (index.column() < data.count()) + return data.at(index.column()); + + return QVariant(); +} + +//! [5] //! [6] +void AddressBookModel::changeItem(const QModelIndex &index, const QString &firstName, const QString &lastName, const QString &address, const QString &email) +{ + Outlook::ContactItem item(contactItems->Item(index.row() + 1)); + + item.SetFirstName(firstName); + item.SetLastName(lastName); + item.SetHomeAddress(address); + item.SetEmail1Address(email); + + item.Save(); + + cache.take(index); +} + +//! [6] //! [7] +void AddressBookModel::addItem(const QString &firstName, const QString &lastName, const QString &address, const QString &email) +{ + Outlook::ContactItem item(outlook.CreateItem(Outlook::olContactItem)); + if (!item.isNull()) { + item.SetFirstName(firstName); + item.SetLastName(lastName); + item.SetHomeAddress(address); + item.SetEmail1Address(email); + + item.Save(); + } +} + +//! [7] //! [8] +void AddressBookModel::update() +{ + cache.clear(); + + emit reset(); +} + + +//! [8] //! [9] +AddressView::AddressView(QWidget *parent) +: QWidget(parent) +{ + QGridLayout *mainGrid = new QGridLayout(this); + + QLabel *liFirstName = new QLabel("First &Name", this); + liFirstName->resize(liFirstName->sizeHint()); + mainGrid->addWidget(liFirstName, 0, 0); + + QLabel *liLastName = new QLabel("&Last Name", this); + liLastName->resize(liLastName->sizeHint()); + mainGrid->addWidget(liLastName, 0, 1); + + QLabel *liAddress = new QLabel("Add&ress", this); + liAddress->resize(liAddress->sizeHint()); + mainGrid->addWidget(liAddress, 0, 2); + + QLabel *liEMail = new QLabel("&E-Mail", this); + liEMail->resize(liEMail->sizeHint()); + mainGrid->addWidget(liEMail, 0, 3); + + add = new QPushButton("A&dd", this); + add->resize(add->sizeHint()); + mainGrid->addWidget(add, 0, 4); + connect(add, SIGNAL(clicked()), this, SLOT(addEntry())); + + iFirstName = new QLineEdit(this); + iFirstName->resize(iFirstName->sizeHint()); + mainGrid->addWidget(iFirstName, 1, 0); + liFirstName->setBuddy(iFirstName); + + iLastName = new QLineEdit(this); + iLastName->resize(iLastName->sizeHint()); + mainGrid->addWidget(iLastName, 1, 1); + liLastName->setBuddy(iLastName); + + iAddress = new QLineEdit(this); + iAddress->resize(iAddress->sizeHint()); + mainGrid->addWidget(iAddress, 1, 2); + liAddress->setBuddy(iAddress); + + iEMail = new QLineEdit(this); + iEMail->resize(iEMail->sizeHint()); + mainGrid->addWidget(iEMail, 1, 3); + liEMail->setBuddy(iEMail); + + change = new QPushButton("&Change", this); + change->resize(change->sizeHint()); + mainGrid->addWidget(change, 1, 4); + connect(change, SIGNAL(clicked()), this, SLOT(changeEntry())); + + treeView = new QTreeView(this); + treeView->setSelectionMode(QTreeView::SingleSelection); + treeView->setRootIsDecorated(false); + + model = new AddressBookModel(this); + treeView->setModel(model); + + connect(treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(itemSelected(QModelIndex))); + + mainGrid->addWidget(treeView, 2, 0, 1, 5); +} + +void AddressView::updateOutlook() +{ + model->update(); +} + +void AddressView::addEntry() +{ + if (!iFirstName->text().isEmpty() || !iLastName->text().isEmpty() || + !iAddress->text().isEmpty() || !iEMail->text().isEmpty()) { + model->addItem(iFirstName->text(), iFirstName->text(), iAddress->text(), iEMail->text()); + } + + iFirstName->setText(""); + iLastName->setText(""); + iAddress->setText(""); + iEMail->setText(""); +} + +void AddressView::changeEntry() +{ + QModelIndex current = treeView->currentIndex(); + + if (current.isValid()) + model->changeItem(current, iFirstName->text(), iLastName->text(), iAddress->text(), iEMail->text()); +} + +//! [9] //! [10] +void AddressView::itemSelected(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QAbstractItemModel *model = treeView->model(); + iFirstName->setText(model->data(model->index(index.row(), 0)).toString()); + iLastName->setText(model->data(model->index(index.row(), 1)).toString()); + iAddress->setText(model->data(model->index(index.row(), 2)).toString()); + iEMail->setText(model->data(model->index(index.row(), 3)).toString()); +} +//! [10] diff --git a/examples/activeqt/qutlook/addressview.h b/examples/activeqt/qutlook/addressview.h new file mode 100644 index 0000000..e1a0b85 --- /dev/null +++ b/examples/activeqt/qutlook/addressview.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ADDRESSVIEW_H +#define ADDRESSVIEW_H + +#include <QWidget> + +class AddressBookModel; +QT_BEGIN_NAMESPACE +class QLineEdit; +class QModelIndex; +class QPushButton; +class QTreeView; +QT_END_NAMESPACE + +//! [0] +class AddressView : public QWidget +{ + Q_OBJECT + +public: + AddressView(QWidget *parent = 0); + +protected slots: + void addEntry(); + void changeEntry(); + void itemSelected(const QModelIndex &index); + + void updateOutlook(); + +protected: + AddressBookModel *model; + + QTreeView *treeView; + QPushButton *add, *change; + QLineEdit *iFirstName, *iLastName, *iAddress, *iEMail; +}; +//! [0] + +#endif // ADDRESSVIEW_H diff --git a/examples/activeqt/qutlook/fileopen.xpm b/examples/activeqt/qutlook/fileopen.xpm new file mode 100644 index 0000000..880417e --- /dev/null +++ b/examples/activeqt/qutlook/fileopen.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *fileopen[] = { +" 16 13 5 1", +". c #040404", +"# c #808304", +"a c None", +"b c #f3f704", +"c c #f3f7f3", +"aaaaaaaaa...aaaa", +"aaaaaaaa.aaa.a.a", +"aaaaaaaaaaaaa..a", +"a...aaaaaaaa...a", +".bcb.......aaaaa", +".cbcbcbcbc.aaaaa", +".bcbcbcbcb.aaaaa", +".cbcb...........", +".bcb.#########.a", +".cb.#########.aa", +".b.#########.aaa", +"..#########.aaaa", +"...........aaaaa" +}; diff --git a/examples/activeqt/qutlook/fileprint.xpm b/examples/activeqt/qutlook/fileprint.xpm new file mode 100644 index 0000000..6ada912 --- /dev/null +++ b/examples/activeqt/qutlook/fileprint.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *fileprint[] = { +" 16 14 6 1", +". c #000000", +"# c #848284", +"a c #c6c3c6", +"b c #ffff00", +"c c #ffffff", +"d c None", +"ddddd.........dd", +"dddd.cccccccc.dd", +"dddd.c.....c.ddd", +"ddd.cccccccc.ddd", +"ddd.c.....c....d", +"dd.cccccccc.a.a.", +"d..........a.a..", +".aaaaaaaaaa.a.a.", +".............aa.", +".aaaaaa###aa.a.d", +".aaaaaabbbaa...d", +".............a.d", +"d.aaaaaaaaa.a.dd", +"dd...........ddd" +}; diff --git a/examples/activeqt/qutlook/filesave.xpm b/examples/activeqt/qutlook/filesave.xpm new file mode 100644 index 0000000..bd6870f --- /dev/null +++ b/examples/activeqt/qutlook/filesave.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *filesave[] = { +" 14 14 4 1", +". c #040404", +"# c #808304", +"a c #bfc2bf", +"b c None", +"..............", +".#.aaaaaaaa.a.", +".#.aaaaaaaa...", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".##........##.", +".############.", +".##.........#.", +".##......aa.#.", +".##......aa.#.", +".##......aa.#.", +"b............." +}; diff --git a/examples/activeqt/qutlook/main.cpp b/examples/activeqt/qutlook/main.cpp new file mode 100644 index 0000000..da5b656 --- /dev/null +++ b/examples/activeqt/qutlook/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include "addressview.h" +#include <QApplication> + +int main(int argc, char ** argv) +{ + QApplication a(argc, argv); + + AddressView view; + view.setWindowTitle("Qt Example - Looking at Outlook"); + view.show(); + + return a.exec(); +} +//! [0] diff --git a/examples/activeqt/qutlook/qutlook.pro b/examples/activeqt/qutlook/qutlook.pro new file mode 100644 index 0000000..c1154e0 --- /dev/null +++ b/examples/activeqt/qutlook/qutlook.pro @@ -0,0 +1,23 @@ +#! [0] #! [1] +TEMPLATE = app +TARGET = qutlook +CONFIG += qaxcontainer + +TYPELIBS = $$system(dumpcpp -getfile {00062FFF-0000-0000-C000-000000000046}) +#! [0] + +isEmpty(TYPELIBS) { + message("Microsoft Outlook type library not found!") + REQUIRES += Outlook +} else { +#! [1] #! [2] + HEADERS = addressview.h + SOURCES = addressview.cpp main.cpp +} +#! [2] + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/qutlook +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS qutlook.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/qutlook +INSTALLS += target sources diff --git a/examples/activeqt/simple/main.cpp b/examples/activeqt/simple/main.cpp new file mode 100644 index 0000000..7d6d340 --- /dev/null +++ b/examples/activeqt/simple/main.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QAxBindable> +#include <QAxFactory> +#include <QApplication> +#include <QLayout> +#include <QSlider> +#include <QLCDNumber> +#include <QLineEdit> +#include <QMessageBox> + +//! [0] +class QSimpleAX : public QWidget, public QAxBindable +{ + Q_OBJECT + Q_PROPERTY( QString text READ text WRITE setText ) + Q_PROPERTY( int value READ value WRITE setValue ) +public: + QSimpleAX(QWidget *parent = 0) + : QWidget(parent) + { + QVBoxLayout *vbox = new QVBoxLayout( this ); + + slider = new QSlider( Qt::Horizontal, this ); + LCD = new QLCDNumber( 3, this ); + edit = new QLineEdit( this ); + + connect( slider, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)) ); + connect( edit, SIGNAL(textChanged(QString)), this, SLOT(setText(QString)) ); + + vbox->addWidget( slider ); + vbox->addWidget( LCD ); + vbox->addWidget( edit ); + } + + QString text() const + { + return edit->text(); + } + int value() const + { + return slider->value(); + } + +signals: + void someSignal(); + void valueChanged(int); + void textChanged(const QString&); + +public slots: + void setText( const QString &string ) + { + if ( !requestPropertyChange( "text" ) ) + return; + + edit->blockSignals( true ); + edit->setText( string ); + edit->blockSignals( false ); + emit someSignal(); + emit textChanged( string ); + + propertyChanged( "text" ); + } + void about() + { + QMessageBox::information( this, "About QSimpleAX", "This is a Qt widget, and this slot has been\n" + "called through ActiveX/OLE automation!" ); + } + void setValue( int i ) + { + if ( !requestPropertyChange( "value" ) ) + return; + slider->blockSignals( true ); + slider->setValue( i ); + slider->blockSignals( false ); + LCD->display( i ); + emit valueChanged( i ); + + propertyChanged( "value" ); + } + +private: + QSlider *slider; + QLCDNumber *LCD; + QLineEdit *edit; +}; + +//! [0] +#include "main.moc" + +//! [1] +QAXFACTORY_DEFAULT(QSimpleAX, + "{DF16845C-92CD-4AAB-A982-EB9840E74669}", + "{616F620B-91C5-4410-A74E-6B81C76FFFE0}", + "{E1816BBA-BF5D-4A31-9855-D6BA432055FF}", + "{EC08F8FC-2754-47AB-8EFE-56A54057F34E}", + "{A095BA0C-224F-4933-A458-2DD7F6B85D8F}") +//! [1] diff --git a/examples/activeqt/simple/simple.inf b/examples/activeqt/simple/simple.inf new file mode 100644 index 0000000..3657e9f --- /dev/null +++ b/examples/activeqt/simple/simple.inf @@ -0,0 +1,11 @@ +//! [0] +[version] + signature="$CHICAGO$" + AdvancedINF=2.0 + [Add.Code] + simpleax.exe=simpleax.exe + [simpleax.exe] + file-win32-x86=thiscab + clsid={DF16845C-92CD-4AAB-A982-EB9840E74669} + RegisterServer=yes +//! [0] diff --git a/examples/activeqt/simple/simple.pro b/examples/activeqt/simple/simple.pro new file mode 100644 index 0000000..d0f2019 --- /dev/null +++ b/examples/activeqt/simple/simple.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = simpleax + +CONFIG += qt warn_off qaxserver + +SOURCES = main.cpp +RC_FILE = $$QT_SOURCE_TREE/src/activeqt/control/qaxserver.rc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/simple +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS simple.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/simple +INSTALLS += target sources diff --git a/examples/activeqt/webbrowser/main.cpp b/examples/activeqt/webbrowser/main.cpp new file mode 100644 index 0000000..4928380 --- /dev/null +++ b/examples/activeqt/webbrowser/main.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QMessageBox> +#include <QProgressBar> +#include <QStatusBar> +#include <QMainWindow> +#include <QAbstractEventDispatcher> + +#if defined(Q_WS_WINCE_WM) +#include "ui_mainwindow_windowsmobile.h" +#include <windows.h> +#else +#include "ui_mainwindow.h" +#endif + +//! [0] +class MainWindow : public QMainWindow, public Ui::MainWindow +{ + Q_OBJECT +public: + MainWindow(); + +public slots: + void on_WebBrowser_TitleChange(const QString &title); + void on_WebBrowser_ProgressChange(int a, int b); + void on_WebBrowser_CommandStateChange(int cmd, bool on); + void on_WebBrowser_BeforeNavigate(); + void on_WebBrowser_NavigateComplete(QString); + + void on_actionGo_triggered(); + void on_actionNewWindow_triggered(); + void on_actionAbout_triggered(); + void on_actionAboutQt_triggered(); + void on_actionFileClose_triggered(); + +private: + QProgressBar *pb; +}; +//! [0] //! [1] + +MainWindow::MainWindow() +{ + setupUi(this); + + connect(addressEdit, SIGNAL(returnPressed()), actionGo, SLOT(trigger())); + connect(actionBack, SIGNAL(triggered()), WebBrowser, SLOT(GoBack())); + connect(actionForward, SIGNAL(triggered()), WebBrowser, SLOT(GoForward())); + connect(actionStop, SIGNAL(triggered()), WebBrowser, SLOT(Stop())); + connect(actionRefresh, SIGNAL(triggered()), WebBrowser, SLOT(Refresh())); + connect(actionHome, SIGNAL(triggered()), WebBrowser, SLOT(GoHome())); + connect(actionSearch, SIGNAL(triggered()), WebBrowser, SLOT(GoSearch())); + + pb = new QProgressBar(statusBar()); + pb->setTextVisible(false); + pb->hide(); + statusBar()->addPermanentWidget(pb); + + WebBrowser->dynamicCall("GoHome()"); +} + +//! [1] //! [2] +void MainWindow::on_WebBrowser_TitleChange(const QString &title) +{ + setWindowTitle("Qt WebBrowser - " + title); +} + +void MainWindow::on_WebBrowser_ProgressChange(int a, int b) +{ + if (a <= 0 || b <= 0) { + pb->hide(); + return; + } + pb->show(); + pb->setRange(0, b); + pb->setValue(a); +} + +void MainWindow::on_WebBrowser_CommandStateChange(int cmd, bool on) +{ + switch (cmd) { + case 1: + actionForward->setEnabled(on); + break; + case 2: + actionBack->setEnabled(on); + break; + } +} + +void MainWindow::on_WebBrowser_BeforeNavigate() +{ + actionStop->setEnabled(true); +} + +void MainWindow::on_WebBrowser_NavigateComplete(QString) +{ + actionStop->setEnabled(false); +} + +//! [2] //! [3] +void MainWindow::on_actionGo_triggered() +{ + WebBrowser->dynamicCall("Navigate(const QString&)", addressEdit->text()); +} + +void MainWindow::on_actionNewWindow_triggered() +{ + MainWindow *window = new MainWindow; + window->show(); + if (addressEdit->text().isEmpty()) + return; + window->addressEdit->setText(addressEdit->text()); + window->actionStop->setEnabled(true); + window->on_actionGo_triggered(); +} + +void MainWindow::on_actionAbout_triggered() +{ + QMessageBox::about(this, tr("About WebBrowser"), + tr("This Example has been created using the ActiveQt integration into Qt Designer.\n" + "It demonstrates the use of QAxWidget to embed the Internet Explorer ActiveX\n" + "control into a Qt application.")); +} + +void MainWindow::on_actionAboutQt_triggered() +{ + QMessageBox::aboutQt(this, tr("About Qt")); +} + +void MainWindow::on_actionFileClose_triggered() +{ + close(); +} + +#include "main.moc" + +//! [3] //! [4] +int main(int argc, char ** argv) +{ + QApplication a(argc, argv); + MainWindow w; +#if defined(Q_OS_WINCE) + w.showMaximized(); +#else + w.show(); +#endif + return a.exec(); +} +//! [4] diff --git a/examples/activeqt/webbrowser/mainwindow.ui b/examples/activeqt/webbrowser/mainwindow.ui new file mode 100644 index 0000000..12a0a32 --- /dev/null +++ b/examples/activeqt/webbrowser/mainwindow.ui @@ -0,0 +1,306 @@ +<ui version="4.0" stdsetdef="1" > + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow" > + <property name="objectName" > + <string notr="true" >MainWindow</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>812</width> + <height>605</height> + </rect> + </property> + <property name="windowTitle" > + <string>Qt WebBrowser</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QFrame" name="Frame3" > + <property name="objectName" > + <string notr="true" >Frame3</string> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Sunken</enum> + </property> + <layout class="QVBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>1</number> + </property> + <property name="spacing" > + <number>0</number> + </property> + <item> + <widget class="WebAxWidget" name="WebBrowser" > + <property name="objectName" > + <string notr="true" >WebBrowser</string> + </property> + <property name="focusPolicy" > + <enum>Qt::StrongFocus</enum> + </property> + <property name="control" > + <string>{8856F961-340A-11D0-A96B-00C04FD705A2}</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QToolBar" name="tbNavigate" > + <property name="objectName" > + <string notr="true" >tbNavigate</string> + </property> + <property name="windowTitle" > + <string>Navigation</string> + </property> + <addaction name="actionBack" /> + <addaction name="actionForward" /> + <addaction name="actionStop" /> + <addaction name="actionRefresh" /> + <addaction name="actionHome" /> + <addaction name="separator" /> + <addaction name="actionSearch" /> + </widget> + <widget class="QToolBar" name="tbAddress" > + <property name="objectName" > + <string notr="true" >tbAddress</string> + </property> + <property name="windowTitle" > + <string>Address</string> + </property> + <widget class="QLabel" name="lblAddress" > + <property name="objectName" > + <string notr="true" >lblAddress</string> + </property> + <property name="text" > + <string>Address</string> + </property> + </widget> + <widget class="QLineEdit" name="addressEdit" > + <property name="objectName" > + <string notr="true" >addressEdit</string> + </property> + </widget> + <addaction name="actionGo" /> + </widget> + <widget class="QMenuBar" name="menubar" > + <property name="objectName" > + <string notr="true" >menubar</string> + </property> + <widget class="QMenu" name="PopupMenu" > + <property name="objectName" > + <string notr="true" >PopupMenu</string> + </property> + <property name="title" > + <string>&File</string> + </property> + <widget class="QMenu" name="FileNewGroup_2" > + <property name="objectName" > + <string notr="true" >FileNewGroup_2</string> + </property> + <property name="title" > + <string>New</string> + </property> + <addaction name="actionNewWindow" /> + </widget> + <addaction name="FileNewGroup" /> + <addaction name="FileNewGroup_2" /> + <addaction name="separator" /> + <addaction name="actionFileClose" /> + </widget> + <widget class="QMenu" name="unnamed" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="title" > + <string>&Help</string> + </property> + <addaction name="actionAbout" /> + <addaction name="actionAboutQt" /> + </widget> + <addaction name="PopupMenu" /> + <addaction name="unnamed" /> + </widget> + <action name="actionGo" > + <property name="objectName" > + <string>actionGo</string> + </property> + <property name="icon" > + <iconset>image0</iconset> + </property> + <property name="iconText" > + <string>Go</string> + </property> + </action> + <action name="actionBack" > + <property name="objectName" > + <string>actionBack</string> + </property> + <property name="icon" > + <iconset>image1</iconset> + </property> + <property name="iconText" > + <string>Back</string> + </property> + <property name="shortcut" > + <string>Backspace</string> + </property> + </action> + <action name="actionForward" > + <property name="objectName" > + <string>actionForward</string> + </property> + <property name="icon" > + <iconset>image2</iconset> + </property> + <property name="iconText" > + <string>Forward</string> + </property> + </action> + <action name="actionStop" > + <property name="objectName" > + <string>actionStop</string> + </property> + <property name="icon" > + <iconset>image3</iconset> + </property> + <property name="iconText" > + <string>Stop</string> + </property> + </action> + <action name="actionRefresh" > + <property name="objectName" > + <string>actionRefresh</string> + </property> + <property name="icon" > + <iconset>image4</iconset> + </property> + <property name="iconText" > + <string>Refresh</string> + </property> + </action> + <action name="actionHome" > + <property name="objectName" > + <string>actionHome</string> + </property> + <property name="icon" > + <iconset>image5</iconset> + </property> + <property name="iconText" > + <string>Home</string> + </property> + </action> + <action name="actionFileClose" > + <property name="objectName" > + <string>actionFileClose</string> + </property> + <property name="iconText" > + <string>Close</string> + </property> + <property name="text" > + <string>C&lose</string> + </property> + </action> + <action name="actionSearch" > + <property name="objectName" > + <string>actionSearch</string> + </property> + <property name="icon" > + <iconset>image6</iconset> + </property> + <property name="iconText" > + <string>Search</string> + </property> + </action> + <action name="actionAbout" > + <property name="objectName" > + <string>actionAbout</string> + </property> + <property name="iconText" > + <string>About</string> + </property> + </action> + <action name="actionAboutQt" > + <property name="objectName" > + <string>actionAboutQt</string> + </property> + <property name="iconText" > + <string>About Qt</string> + </property> + </action> + <actiongroup name="FileNewGroup" > + <action name="actionNewWindow" > + <property name="objectName" > + <string>actionNewWindow</string> + </property> + <property name="iconText" > + <string>Window</string> + </property> + <property name="shortcut" > + <string>Ctrl+N</string> + </property> + </action> + <property name="objectName" > + <string>FileNewGroup</string> + </property> + </actiongroup> + </widget> + <customwidgets> + <customwidget> + <class>WebAxWidget</class> + <extends>QAxWidget</extends> + <header>webaxwidget.h</header> + </customwidget> + </customwidgets> + <connections> + <connection> + <sender>addressEdit</sender> + <signal>returnPressed()</signal> + <receiver>actionGo</receiver> + <slot>trigger()</slot> + </connection> + </connections> + <layoutdefault spacing="6" margin="11" /> + <images> + <image name="image0" > + <data format="XPM.GZ" length="1241" >789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade65232365200210543251d2e253d856405bffcbc54103b11c8563600020b03105719c4b530b08072f50880513560a09c080338d5209420294a4451a38c90426621ab5146d10de524a2aa417505445122861a547722bb0c971a3d2aa921c2ae446c6a9431fc85a9064551220e354009653dec00294e712a1ac4e97078a9a9b5e6020013b3f563</data> + </image> + <image name="image1" > + <data format="XPM.GZ" length="4494" >789ce596497332470c86effe15947573a5f4c1cc30cc542a07ef60bc808dd7540e3d9b6df006186c93ca7f8fba2535ce57be98dc9292313c487a2575f7ccf063a376d53baa6dfc589bbe9ad7fbbc96df99496da3983d3e7efcfec76f7faead87418dfe1a51500bd67f595befbfd6f2daf1f35369014e08a05e6fd4ab96e31e73d0282bc7a7cae23ff3ccfe8170ca6cee9843f51f3b4ec8cff9efccdebf2d2cf9b06bb9417a25c74f98bdff99390a84fb8e49af70f39891b2e40bfbf8b6b0917e87968346a8f5a6cc51c07ab02f2cf1983237552f709c86691e3bbd5be5821998a32067bd1765d13f67563d530a4b3df8b01c523d8ec74059faed086bfc82390e851b8ed3c86485e34365a9bfc5ece3df8433e10bcb5140f5dd3cf0e099f32f99e350cecb5858f2b1c1dc52fda663d334a277c0ecfd5d61c9373973120967969b548fd71b079e797d8e985b21eb63aecceb85e7c299f4ffaa2ce7739359ebc195631387c6ad1f5e302791ccbba72cf173e15cfa2d2cc7619cf1fa63c9dccaa4ff4bcfdc7fa82cfdf7999348f6bf299c4bfd4c59ea0f99535dafca71d60a65ffebca52ff8c3989e47cce98351fb785759e7bcbad65bf0be624ca9a8e87caac0fb1702ef191b2cc9731a7b9ec4f87d934659e27e142f8c671e6eb9d0ae7b2be07cc6924ccf999698a7e4f58f572e64cebb9f393444994e68e4365d9ff7be15caef70766ad678cb0f8f18359ebe109b3af27f199fadd794cf254eb196599774758e77d5496f5dd64a67959af122ef87c639b59eb81d34ba97fe3f4215196f3922acbbc28acf527cc792c7a857029ecf63bcded05efb8a52cf3cc9833ed2f66563dac0b8b1ebe3317ea77f73352173db8f6ccf54a66df0f30fb7c777d9bc214d2cf88d9cf73cfece3ddf3296b66da7fe199d7a32b5cc8feef31fbfe8f99bdde96b0faddf3272bac390665b99e90d9e7ef33972de9d73d7ff3d873255c49fc1b73257ee4f8d2eb5d336b3e8e8535ff86d9e7bbf35f2cf51366ef77cfeb6299df62563f3c0a8b1fdcf3d3569778773f756e66f7fcac967e175f797ffff5dfd9ff4103010d6698a35955030b2cb1c25bbcc3fbd5344861882352b8c5077c5c45836678c267ca7fc1314ebeaf81537cc599eb608e6ff88e1f2b682c705314b6486182dbb8f31d0ddca529f644619ff2db641d3cf82a8bfa9d62d7da670d3cc4233c760a63eaa08d2734478fac8f87ffc833788a6738c073bc20ebe3255eb1069d863e5e3b851bacfb7c6b0d0c30c488f24a3a2d4ddaf1986a3d600b13179be280ef597809e876e206000c69d8ec0e590f32c8a18012b7a0825b9799e018eee0de4e0b4318c103ff2ea2985b78c47d28a487ce276b634cca40356d1655801c3bf044af2136e0195ef8b711be4045ab50ff42e16bdbb6463d8e610253fe3d4855ec3ed80abd9f62397ef9c9e6cee835249bc31bbc731ff0010beacbcdbfaca29f2836a3e839fd1f3acb5cb6fd6e13b6605b34766097d6664cdf0d7faad9813dd827df08daf4de812ddaa7061c4017baf43ea6daef70c8fb0247704c932dc897b94e67da09553a811ef4a94a0f4ee10c069435216b630ae7a43b800b7fc6164ea543ea73ea75663b22a50e5cc215ec50956beaf606ead08080147b64c76403d20ebdc6142268528d3655ee3a1db6f88b535ee015b42081d4205ee1f4f335878501ea7644331dc81acecdb7ef63b86b32eae59956cff63237f92af7319c9a82669c989256bd0b6fa6fabe86bbfe0ecdadb9a399ce61b49a86355adfbedd45736756bc27b30afd161a9a9179585de33bf69fd2f8ebd7b5bf014644b906</data> + </image> + <image name="image2" > + <data format="XPM.GZ" length="4494" >789ce5965b4f23471085dff915d6d6db2aaac5e3b92aca037703cbc55c8c21ca43cf8c8d0dd85c6c307694ff9eeaaed3bd68771f968d14298a0a109fabebd4e99a9ef17cfad8e81d1f343e7e5a99cecc6c5435aaa1796a7cac9fc7e3c5ef7ffcf6e7ca8756d4909f661c35a20fbfac7ce8cc1a55e3f07ed2b7409702b4badaccfb996563020f5c7ecbf340b9a31c3591dff7ac7943e002cc8e73cf74acdcc27a8a2d37a5be4e1d9f04567f9fc105f25dcfea9726caad62a07c1158f58f94e3087e868ea57fa5fa0be590bfb11c3525affd4e03ebfa25b8507fbcaa1c47ca66e459fdf10c6c30af4dcfda8f5f9513dfffce71e1f5a956967adddfaeb25f4f7b60e8d199e596f42f6bc787ca213f554e5be06dc7a28ffdee282791cedb5c83d19fd795a55ecf4b3fb0ee07ebd312fae796e3283665e238524e2265de031bcc774d396d61be25b8c4fe1f02abfeab67f49f2867decfbd6393b6a03f03438f3bca19fa51cb33fc6f80fd7eae2c27e257e7cb4de5b4045f78d679f24960ddcfb172e6f73357ce63e88fc115ce43e558fcabbeb905fb7e47cae24ff5daca41af007bbd81e5b425f53aff6160d52f95f318f37d01a39ee7ca05f4790a469e0e1c97590bfa1b81f53c3e2bfbf5ecf697b532efe754398f31af437085eb65948b18e723f70cbf9e2bcc633db0f65b533609fcbafb372bf318fdcfc015e65b281731ee0ff6acf70767ca5e8f7be01abcab5cfa7e89e53cce2ba3fd1681b5df8172013f44e00acfbf4a39e8ef287b7dbe02234feefce795d727a36c12ccf75239d4b7c1bede9def42fcc0ef7960d5cbc05ebf543635aed752b94aa1ff02ee83ddf3b6a87c3d3f2b9b047a4fcaa17e0cf6f5eef928ab13f5476960d5eb7ac6f5dd07d7e04839e83d29d7be9ffbfe31b50dc723cfa87f08acf947e51a7ad457ee6760773ecaa4f47e36036bfd96673c3fb6c13578a01cf41f9505d5af3b2f655dc28fa93da33e550ef523e5e06f08861eb9e7b94cdfe7ddf753d50feb6f94437e00f67edcf3aa4e831ed8afe73bb05fefe655f7c37edcfd62bb81ddfb82935776cfeb41c87766ff2cfe7f1a4c6cb8e48ae91f68d4dce7015ff390473fad71c3b77cc7639ef03d3ffcb48f013ff293a84c79c6d54f693c8bc28b28589539bff2e2ed647e586389184bacf13a6ff0e6d71a32f92dde96bfdf9dbccc6387dba2d086caae4c668ff7bf68f0673ee0433ee263eef0099ff2199f8b62d0e32e5f704fea2fe5b70d3f57729556b91b349a1c718b634e64faa9fc7fc919e772220a91213254ca273b884bf72b4a54f1846ad925e93b1af56940d734a4110fe4efb5c40dddda907311734c7752d10b3a1ae289c634a17b7dafe331e995b3b124fbdfd25d85471763596fab7aa2a4f53d444653ded3773bb96e8faeae1de2ea8dff9da0b0ebfcd858e3357aa667bb1f68b4a5e7d256853559e8f56d64aefe85e6f44a0b5aea3bac5c2bebf74b8775fb6bfbb858771e7a6f1df09c36f89a36698bb6f53d5c4ef08ee4e6a2dd269b9d488729ed4a171b7bd40ece3228cce5d305edd3673ed7773139bd133a14d5233a96cff7a9237142a77446e7125dba900e70681564f5a6acdc1285ae9e0feaf150d675e8d2d59dd315ad52931fec2973d1a5489c6698e29c5a508829797bd629a52665bcf9fdd32ed95c1d50217b5c18b67390f34befb8e78873a9b6b39ad285216328a2de3bef5b32a59db5ccec42a6b565aaf7dffba6e663d3972b211ea86b065f3cbccbc7b53890399a21a55f677f5863e4f670c337df667f58e3d6dc99dbef3dd5ff6bdf73ff82c65fbfaefc0d4fb5b868</data> + </image> + <image name="image3" > + <data format="XPM.GZ" length="802" >789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade65232325500210543251d2e25658564056503300071f540dc3430007371012a492a830156496538c094848922c9c2259134c099304914e3604c8424aa5e6449b0044216ca824ba2da8b4512218b4d122e8b55520fee5974072164511da487ea490c7f22cba249e20d3efc018f3fcae0d2702eb5d2106992b5d65c00b9a48974</data> + </image> + <image name="image4" > + <data format="XPM.GZ" length="1241" >789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade65232365200210543251d2e253d856405bffcbc54105b19c8563600020b03103711c4b530b08072f50880513524ab518681443435ca984ae08ae06a94114a10ac443435ca3043904d4c4453a38ca604ae11590d9a0ab80bd0d46078914c35c4d885a608871a547f61f81d5d117a1862018930e5b8d5c0950c741a1b1e6a6aadb90086a9d853</data> + </image> + <image name="image5" > + <data format="XPM.GZ" length="5598" >789ca5985973db480ec7dff3295cc15b6a0b2351a428d6d63ef83e255bbe647b6a1fd02465dd872d9f53f3dd076c005dc926ce6a32eed8553f37fadf7fa0c1a69cdfbe6cdc9cb537befcf6e97145ab61be910fe861e34bf1349dbefdfedffffcf1e97323dae07f51bdbe117dfed7a7cfddd546bed199cfca0ae888016afeab62e8796ef110ee545caf05be16ae5bfc6ee096e7b6e756983f51b6f53b81257ecfb8eee7e9b162f66af1c78125fe48987f23f3fb81657e691cd5bddecc7316d555efd058f7eb2867aa771058f4de8c55cffb6dd4a34cf5b68d357e681c6515634db81a7e3ef59c35cccf5560bf9ef6953389c77660af074f15c751e05c38a6d81f2ef9f3a848f4e9d658f2c36b635dbfa54cc2383556bd33e12492fc70df38f1f3f8ae4cc2745a711285fda7caa4f95e06967a2d8c63f27a8fc2a60fa4acfa980a371b898f0767dc6cf8fdbc9f84c27e4de124d2fabe186b3dee8c75ff1365dbef2db0ccef0987fd2f2a6632fd576552fd2b63d57b08ecd7d39d70b321fd0560acfb6d1a4b7e3050764de7d79f08a70de937ea7b7689e68f4de1e0776e2c7ab8abecb47eb170aa7ee822b0e89f1b4b7fd24dc529abe9794f02cbf99e2b3badc7a5b1ee97089b3e0e8d253f3c364e253e5576120ff7c63a9f7966d2e771d358e75bca4ef3bb0e2cf9758db5fe47c6b21eeb81bd3f07c2ad58ebd130d67e6a194b3cf97e62b2fa24c67a1f5d2aab3f8781a53e17c6eaa7082cfa3de156acf9d5034b7e3563f1eb96c6eaf7c0b815fbf8d2739e3aedefb1b1de9723618b77a49cebf946c6e20f5f8d251e753e8b5bb9e74c980a4afc7a7fbf66b1ed8fb7c67a9ec7c2ad5cfd74038bdfa6b1f6cbd458fd2e84b358efbb0363f5b71358fccd8c33596f9c4bfddcc458fac78d8cf5797b3296f5f82c4c49e6f5c9bf9fb23ce41307967e3935d6f36c0b67b1ce3f188b5f3757367f5363b98fdc38b0cc0f8cf5f90bf3ea97028bfe50981289777d63edcf81b1c4439897f3c52d615738cfe0df371c1deb7db265acf98d8d253f7a50d67a60c758cfcbf4cc7f2fb0f8bf1736bfae30d6f35f1a4b3ce6c6e2df95ca85f6f7dc58f3db0e5c783e14e6ebc533e87e963fbe0873f9fd3cc97c91693fd028b0d4e3c558f3eb0b9b5f972bab3fe78c353f3056bfabc0e2371636bfe4cf9b29d1e76b69acfdb863accfd33cb0dc2fa7c6e2179e03cb79ae940b7dffbf1b6bfd1363f53b12367f581a6b3d1bca56df6e60a9bfc6e765def4ecef6bc7eafaf9e8d558fbb7a15ce87d7263acf7ffbdb1e40f33e1e0cf29ebfea8eb6d7ff29f17f8f4137dfe51d8fa0117ca65ee3fbfe3bd705116b2de9f775e3af50313e1a229f1f0682cf1b052e6e1d9dfbf1cddd4fd2363cdcfef5fb05b7d1f0c944bed4f67ac9f5f27c265bf4c3d9f07eefb787f1f96695eaa1e0a174d7d7f81b1ee4f81a5fe75e552d9bf1fca7e617e9e8d556f33b0c4fbcf5ffdb44c956bc6a2d75dfd6c2020fd3ce2ff69a0c31c0b2cff91461fef71804374bfaa81231ce3044b9ce2ecd734380fc2392e70890ff888bfa6f184cff8c24e5ef10ddf71f3a37c3ed6c015afdec26dfeb983bbb887fb78f0f734380fe031c7437f3247788c27d8fe713e1f6a1076f014cfb08be7ac7481977885d75c951fe4f3630dcea3c3eb7b9cc70d6b9ce12d9fee26de610debeb69b0fb578cb89a0d8c399711e794609373d9c39455f2b53466d8c20c17809c45cc7a3c00f011081cffccff379fef35388f1d0428a0c401f459e58c3d45700f0003cee71d8678fc730d7430e2557d3c8331f7568c37308129cc7006733e9d262c6008cb6ff3f94ea3c72bc678ca3f1fb80a637884154c71c974c55d72c91a4feca4fdf553f8ad46554d8e9ee30a9eb1efab31611f2ff0ca346427bb9c11e114debe7e7ebed328318702e7f0ce9dbee47a1c724655b745b0c94ea6b0c55519f059b98f73d19a6cc30eecc21eecfb7100877004c770026de8e070bdfe805338832e9cc3055cc2955f7b0d3de8f0cfebb5356ee016eea0c6a30e11342086049a907aadcd35355a90111250f5e5288706bfdb4bea572a78b49e06ddd3a0d2807a2502110d6944639ad09466ebf9e8ae684e0bf5b1a4075ab28f11ffa1df678dc7f57cb0c68a9ee899355e7c2ddbf40a31bdb1c63bcdfe86c6803669cb9f4555c76b38a76dcee57d5d1f5c8f1d5af0b9745581bb029a5c8f3eedd21eed73b70ebe56fa91061dd061f05139e9d1116b1cfb9aee55c4fcf6330d5cd289d778a6b65fdd831dea702e256b9cf2b974a84367d4fd580347744e17744957acc13e7cfc095d538f356ed8cd2ddd518dea147da4c1956890ffcf295ed5e4c83b4a59f182b9455935e3b801ab791c7fa4e188d7a4bcbee66353feaef9df8852ca2f3e9ee3ef73840f359cabfec22979f4ddbd1bf018ba118f318f899bf298b9b95bb8e537cffe9ffffef4171c39a0bf</data> + </image> + <image name="image6" > + <data format="XPM.GZ" length="3742" >789c8d96c9521c490c86ef3c458775734cc8ddd5b5c6c41c303b180cc60b66620eaacc2c9aa5599b7562de7da45fc5180c8e98fa39f091522e4a49c9bbb783bdedcdc1db77735733991d864198c8e5e06dbc9e4eeffffceb8fbfe7de64d9407f466531c8defc36f76667360883adb3d364c013051ae2039f8147266359068f4dc6740a2e4db05f05d726f0253898c017c6a3cc04ffafce79aa3af0143c36c17e055caa0aacbf06aeb2203e5f09ae4d185f75ce472de6e7737063c2fcb57356b702fed673e32c473d4bcf3760198f02e69325706b022f3a676df0f567e05035d1ed273dc79883e7c1d1045e70ae2456d84fd9738a589f0b703261bc72ae25e17ee4b0e7d8f3b5733374e603e32c37c11ff36970db12f193f7e07c1c6bec87c6e0c604ff0e1c4db03f36cec7e3a6f4fd2e38e779eee7bd05e7e350fa7e4fc0455ee6b84fb9eab913bfdf1c5ce5758efba54fffb1e75302d726f8af3817a5f8f922584cf06fc0211f951ebfd0b30afe07ce4510dfdf1e38e665e9f9f1e01c32cf1fda06a73c2f7c7eac5f8c8b61eef582f315b909dc82f1c17e07dc1459e5f1c77d953abb787e0ab832611cf957366dd9c707f556762a3fcf8673ddd6d8afdc1957b909fe98af2a65d4c787c08d09e3c8bfaad504f378de83a309e35fc049d9d747bda19c7dbe8f602d88d6fd11af3a33c1ffde398e02ec69178c0b04bb7fa12be03e08e7ab4b895e2f74ec1ca2e73f6d811b2d37df1feaa9969082f71ff4a73a98c01f9cdb3678fde27eea58f7f9cdc8bfba33c11efda2199ac01bcead048fd72678a4e9e3f6a86f6d172acc87fc69f290f9386f3d72f478a1bf348509fea8b7a66c9b80fec1a8b7a66a53f47cc2fe9b5ae77346fe35ad09e761703081d12f9b68c2fc57ce6d0c1e6fe463934ce0efc63234c11ffd5b4a13c66f9cb53d79fded832bcd27f47f5aeb59055e744eb1df3fe2251aeee4e7453f9264c27aa847b44f7f4f909fda3efb7ae30c5c84b65f1fef435b9a608ff7a4ad4c981ffb6b6b13d8fda5edfb37eff4dcb65e2f787f5a7cb0f7fd0413ecf13eb49d09f6783ff07cf97d8ec0a3f8d8df516f483faf07c45b1f27e9f30ff989e9fdbe11ff1034fd3c9eebe068c238fa9f6677f2fb27ac1f475dd3f97da25fc6c204be755673ef3f8db3360c1f1f824b13c651df2877c44fd0df511efe5ea39f44318151cf9a4e2ab0af870d63fee4dc55fdfe109f880ff3fb788a8ff98df733762630fa471aa6febda2839e5b3f0fe1bef4f18bc9fb01fa7dca4ce0bb9e5b671ef69c3cff18f99cc626d853cf551f3fe453ca531bbdde979cbb2c793e207f536102a39fa5ca0446bf4279f97b89feaabb5181511f38bedf2ffa47373461bdcfe0dc8471d46387860fc6fbaad155c11ef7a5d953747ede69cf2a30fe3fd06c5121fe88572726f8a37f68720ffbfdadf7ac02fb7e82098c7e85ebf2fde37dea92098cf7acc367bc33fbff7a6ecfc4c22d078eaac41d1ff0e4d7f66a7df84293e71ecfec858f9ee8d1fef8a9c733fb139ef2299ff1395ff0255fc167c233befee1f1cc3ef10ddff21ddff303cfabe77bd584177891971e3d7ed8db4e7b2df30aaff29a7aac3ff9ebe4a9bdf2067fe04ddee28ffafb36eff027de558fcfbaab2ffc95bf3db5578b3dfecefb3ce411673c56ceb9e0b23f47a5fbac7fb26f889988742f2a129e504b81a246e0c8ec293cb7a7441d0b1dd0840ee9883486744253bea4533a7bd5fe9c2ed4feb29fff4aff32a36b8dd5e92fe6bfa15bddcf1dddd303cd93c6911668aa2b5cbc363f3c16799f9630fbb2d20aadd21aadeb3d547a8617f6f0d8a00fb4495bfadb47daa61dfa84f977e933c597f64f6e6c9fbed057fa467bf49df669c8bb34a2eca53d8d35576ef88e722aa8a48a6a6a448320a20fd36bf3eb7f407c2c89efb5500f6422877224c77222533915e6b397fbd117f54ccee54275295732936bb9915bb9937b797869ff34e7649ecfe4bd2ce81a8bbc2a4bb2fc5a3dfe2c59915559fb75fdfe8f7affe7f7b97f011cdd9635</data> + </image> + </images> +</ui> diff --git a/examples/activeqt/webbrowser/mainwindow_windowsmobile.ui b/examples/activeqt/webbrowser/mainwindow_windowsmobile.ui new file mode 100644 index 0000000..98a9ddb --- /dev/null +++ b/examples/activeqt/webbrowser/mainwindow_windowsmobile.ui @@ -0,0 +1,299 @@ +<ui version="4.0" stdsetdef="1" > + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow" > + <property name="objectName" > + <string notr="true" >MainWindow</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>812</width> + <height>605</height> + </rect> + </property> + <property name="windowTitle" > + <string>Qt WebBrowser</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QFrame" name="Frame3" > + <property name="objectName" > + <string notr="true" >Frame3</string> + </property> + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Sunken</enum> + </property> + <layout class="QVBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>1</number> + </property> + <property name="spacing" > + <number>0</number> + </property> + <item> + <widget class="QAxWidget" name="WebBrowser" > + <property name="objectName" > + <string notr="true" >WebBrowser</string> + </property> + <property name="focusPolicy" > + <enum>Qt::StrongFocus</enum> + </property> + <property name="control" > + <string>{F5AFC7EF-1571-48B6-A69C-F1833F4C3A44}</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QToolBar" name="tbNavigate" > + <property name="objectName" > + <string notr="true" >tbNavigate</string> + </property> + <property name="windowTitle" > + <string>Navigation</string> + </property> + <addaction name="actionBack" /> + <addaction name="actionForward" /> + <addaction name="actionStop" /> + <addaction name="actionRefresh" /> + <addaction name="actionHome" /> + <addaction name="separator" /> + <addaction name="actionSearch" /> + </widget> + <widget class="QToolBar" name="tbAddress" > + <property name="objectName" > + <string notr="true" >tbAddress</string> + </property> + <property name="windowTitle" > + <string>Address</string> + </property> + <widget class="QLabel" name="lblAddress" > + <property name="objectName" > + <string notr="true" >lblAddress</string> + </property> + <property name="text" > + <string>Address</string> + </property> + </widget> + <widget class="QLineEdit" name="addressEdit" > + <property name="objectName" > + <string notr="true" >addressEdit</string> + </property> + </widget> + <addaction name="actionGo" /> + </widget> + <widget class="QMenuBar" name="menubar" > + <property name="objectName" > + <string notr="true" >menubar</string> + </property> + <widget class="QMenu" name="PopupMenu" > + <property name="objectName" > + <string notr="true" >PopupMenu</string> + </property> + <property name="title" > + <string>&File</string> + </property> + <widget class="QMenu" name="FileNewGroup_2" > + <property name="objectName" > + <string notr="true" >FileNewGroup_2</string> + </property> + <property name="title" > + <string>New</string> + </property> + <addaction name="actionNewWindow" /> + </widget> + <addaction name="FileNewGroup" /> + <addaction name="FileNewGroup_2" /> + <addaction name="separator" /> + <addaction name="actionFileClose" /> + </widget> + <widget class="QMenu" name="unnamed" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="title" > + <string>&Help</string> + </property> + <addaction name="actionAbout" /> + <addaction name="actionAboutQt" /> + </widget> + <addaction name="PopupMenu" /> + <addaction name="unnamed" /> + </widget> + <action name="actionGo" > + <property name="objectName" > + <string>actionGo</string> + </property> + <property name="icon" > + <iconset>image0</iconset> + </property> + <property name="iconText" > + <string>Go</string> + </property> + </action> + <action name="actionBack" > + <property name="objectName" > + <string>actionBack</string> + </property> + <property name="icon" > + <iconset>image1</iconset> + </property> + <property name="iconText" > + <string>Back</string> + </property> + <property name="shortcut" > + <string>Backspace</string> + </property> + </action> + <action name="actionForward" > + <property name="objectName" > + <string>actionForward</string> + </property> + <property name="icon" > + <iconset>image2</iconset> + </property> + <property name="iconText" > + <string>Forward</string> + </property> + </action> + <action name="actionStop" > + <property name="objectName" > + <string>actionStop</string> + </property> + <property name="icon" > + <iconset>image3</iconset> + </property> + <property name="iconText" > + <string>Stop</string> + </property> + </action> + <action name="actionRefresh" > + <property name="objectName" > + <string>actionRefresh</string> + </property> + <property name="icon" > + <iconset>image4</iconset> + </property> + <property name="iconText" > + <string>Refresh</string> + </property> + </action> + <action name="actionHome" > + <property name="objectName" > + <string>actionHome</string> + </property> + <property name="icon" > + <iconset>image5</iconset> + </property> + <property name="iconText" > + <string>Home</string> + </property> + </action> + <action name="actionFileClose" > + <property name="objectName" > + <string>actionFileClose</string> + </property> + <property name="iconText" > + <string>Close</string> + </property> + <property name="text" > + <string>C&lose</string> + </property> + </action> + <action name="actionSearch" > + <property name="objectName" > + <string>actionSearch</string> + </property> + <property name="icon" > + <iconset>image6</iconset> + </property> + <property name="iconText" > + <string>Search</string> + </property> + </action> + <action name="actionAbout" > + <property name="objectName" > + <string>actionAbout</string> + </property> + <property name="iconText" > + <string>About</string> + </property> + </action> + <action name="actionAboutQt" > + <property name="objectName" > + <string>actionAboutQt</string> + </property> + <property name="iconText" > + <string>About Qt</string> + </property> + </action> + <actiongroup name="FileNewGroup" > + <action name="actionNewWindow" > + <property name="objectName" > + <string>actionNewWindow</string> + </property> + <property name="iconText" > + <string>Window</string> + </property> + <property name="shortcut" > + <string>Ctrl+N</string> + </property> + </action> + <property name="objectName" > + <string>FileNewGroup</string> + </property> + </actiongroup> + </widget> + <connections> + <connection> + <sender>addressEdit</sender> + <signal>returnPressed()</signal> + <receiver>actionGo</receiver> + <slot>trigger()</slot> + </connection> + </connections> + <layoutdefault spacing="6" margin="11" /> + <images> + <image name="image0" > + <data format="XPM.GZ" length="1241" >789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade65232365200210543251d2e253d856405bffcbc54103b11c8563600020b03105719c4b530b08072f50880513560a09c080338d5209420294a4451a38c90426621ab5146d10de524a2aa417505445122861a547722bb0c971a3d2aa921c2ae446c6a9431fc85a9064551220e354009653dec00294e712a1ac4e97078a9a9b5e6020013b3f563</data> + </image> + <image name="image1" > + <data format="XPM.GZ" length="4494" >789ce596497332470c86effe15947573a5f4c1cc30cc542a07ef60bc808dd7540e3d9b6df006186c93ca7f8fba2535ce57be98dc9292313c487a2575f7ccf063a376d53baa6dfc589bbe9ad7fbbc96df99496da3983d3e7efcfec76f7faead87418dfe1a51500bd67f595befbfd6f2daf1f35369014e08a05e6fd4ab96e31e73d0282bc7a7cae23ff3ccfe8170ca6cee9843f51f3b4ec8cff9efccdebf2d2cf9b06bb9417a25c74f98bdff99390a84fb8e49af70f39891b2e40bfbf8b6b0917e87968346a8f5a6cc51c07ab02f2cf1983237552f709c86691e3bbd5be5821998a32067bd1765d13f67563d530a4b3df8b01c523d8ec74059faed086bfc82390e851b8ed3c86485e34365a9bfc5ece3df8433e10bcb5140f5dd3cf0e099f32f99e350cecb5858f2b1c1dc52fda663d334a277c0ecfd5d61c9373973120967969b548fd71b079e797d8e985b21eb63aecceb85e7c299f4ffaa2ce7739359ebc195631387c6ad1f5e302791ccbba72cf173e15cfa2d2cc7619cf1fa63c9dccaa4ff4bcfdc7fa82cfdf7999348f6bf299c4bfd4c59ea0f99535dafca71d60a65ffebca52ff8c3989e47cce98351fb785759e7bcbad65bf0be624ca9a8e87caac0fb1702ef191b2cc9731a7b9ec4f87d934659e27e142f8c671e6eb9d0ae7b2be07cc6924ccf999698a7e4f58f572e64cebb9f393444994e68e4365d9ff7be15caef70766ad678cb0f8f18359ebe109b3af27f199fadd794cf254eb196599774758e77d5496f5dd64a67959af122ef87c639b59eb81d34ba97fe3f4215196f3922acbbc28acf527cc792c7a857029ecf63bcded05efb8a52cf3cc9833ed2f66563dac0b8b1ebe3317ea77f73352173db8f6ccf54a66df0f30fb7c777d9bc214d2cf88d9cf73cfece3ddf3296b66da7fe199d7a32b5cc8feef31fbfe8f99bdde96b0faddf3272bac390665b99e90d9e7ef33972de9d73d7ff3d873255c49fc1b73257ee4f8d2eb5d336b3e8e8535ff86d9e7bbf35f2cf51366ef77cfeb6299df62563f3c0a8b1fdcf3d3569778773f756e66f7fcac967e175f797ffff5dfd9ff4103010d6698a35955030b2cb1c25bbcc3fbd5344861882352b8c5077c5c45836678c267ca7fc1314ebeaf81537cc599eb608e6ff88e1f2b682c705314b6486182dbb8f31d0ddca529f644619ff2db641d3cf82a8bfa9d62d7da670d3cc4233c760a63eaa08d2734478fac8f87ffc833788a6738c073bc20ebe3255eb1069d863e5e3b851bacfb7c6b0d0c30c488f24a3a2d4ddaf1986a3d600b13179be280ef597809e876e206000c69d8ec0e590f32c8a18012b7a0825b9799e018eee0de4e0b4318c103ff2ea2985b78c47d28a487ce276b634cca40356d1655801c3bf044af2136e0195ef8b711be4045ab50ff42e16bdbb6463d8e610253fe3d4855ec3ed80abd9f62397ef9c9e6cee835249bc31bbc731ff0010beacbcdbfaca29f2836a3e839fd1f3acb5cb6fd6e13b6605b34766097d6664cdf0d7faad9813dd827df08daf4de812ddaa7061c4017baf43ea6daef70c8fb0247704c932dc897b94e67da09553a811ef4a94a0f4ee10c069435216b630ae7a43b800b7fc6164ea543ea73ea75663b22a50e5cc215ec50956beaf606ead08080147b64c76403d20ebdc6142268528d3655ee3a1db6f88b535ee015b42081d4205ee1f4f335878501ea7644331dc81acecdb7ef63b86b32eae59956cff63237f92af7319c9a82669c989256bd0b6fa6fabe86bbfe0ecdadb9a399ce61b49a86355adfbedd45736756bc27b30afd161a9a9179585de33bf69fd2f8ebd7b5bf014644b906</data> + </image> + <image name="image2" > + <data format="XPM.GZ" length="4494" >789ce5965b4f23471085dff915d6d6db2aaac5e3b92aca037703cbc55c8c21ca43cf8c8d0dd85c6c307694ff9eeaaed3bd68771f968d14298a0a109fabebd4e99a9ef17cfad8e81d1f343e7e5a99cecc6c5435aaa1796a7cac9fc7e3c5ef7ffcf6e7ca8756d4909f661c35a20fbfac7ce8cc1a55e3f07ed2b7409702b4badaccfb996563020f5c7ecbf340b9a31c3591dff7ac7943e002cc8e73cf74acdcc27a8a2d37a5be4e1d9f04567f9fc105f25dcfea9726caad62a07c1158f58f94e3087e868ea57fa5fa0be590bfb11c3525affd4e03ebfa25b8507fbcaa1c47ca66e459fdf10c6c30af4dcfda8f5f9513dfffce71e1f5a956967adddfaeb25f4f7b60e8d199e596f42f6bc787ca213f554e5be06dc7a28ffdee282791cedb5c83d19fd795a55ecf4b3fb0ee07ebd312fae796e3283665e238524e2265de031bcc774d396d61be25b8c4fe1f02abfeab67f49f2867decfbd6393b6a03f03438f3bca19fa51cb33fc6f80fd7eae2c27e257e7cb4de5b4045f78d679f24960ddcfb172e6f73357ce63e88fc115ce43e558fcabbeb905fb7e47cae24ff5daca41af007bbd81e5b425f53aff6160d52f95f318f37d01a39ee7ca05f4790a469e0e1c97590bfa1b81f53c3e2bfbf5ecf697b532efe754398f31af437085eb65948b18e723f70cbf9e2bcc633db0f65b533609fcbafb372bf318fdcfc015e65b281731ee0ff6acf70767ca5e8f7be01abcab5cfa7e89e53cce2ba3fd1681b5df8172013f44e00acfbf4a39e8ef287b7dbe02234feefce795d727a36c12ccf75239d4b7c1bede9def42fcc0ef7960d5cbc05ebf543635aed752b94aa1ff02ee83ddf3b6a87c3d3f2b9b047a4fcaa17e0cf6f5eef928ab13f5476960d5eb7ac6f5dd07d7e04839e83d29d7be9ffbfe31b50dc723cfa87f08acf947e51a7ad457ee6760773ecaa4f47e36036bfd96673c3fb6c13578a01cf41f9505d5af3b2f655dc28fa93da33e550ef523e5e06f08861eb9e7b94cdfe7ddf753d50feb6f94437e00f67edcf3aa4e831ed8afe73bb05fefe655f7c37edcfd62bb81ddfb82935776cfeb41c87766ff2cfe7f1a4c6cb8e48ae91f68d4dce7015ff390473fad71c3b77cc7639ef03d3ffcb48f013ff293a84c79c6d54f693c8bc28b28589539bff2e2ed647e586389184bacf13a6ff0e6d71a32f92dde96bfdf9dbccc6387dba2d086caae4c668ff7bf68f0673ee0433ee263eef0099ff2199f8b62d0e32e5f704fea2fe5b70d3f57729556b91b349a1c718b634e64faa9fc7fc919e772220a91213254ca273b884bf72b4a54f1846ad925e93b1af56940d734a4110fe4efb5c40dddda907311734c7752d10b3a1ae289c634a17b7dafe331e995b3b124fbdfd25d85471763596fab7aa2a4f53d444653ded3773bb96e8faeae1de2ea8dff9da0b0ebfcd858e3357aa667bb1f68b4a5e7d256853559e8f56d64aefe85e6f44a0b5aea3bac5c2bebf74b8775fb6bfbb858771e7a6f1df09c36f89a36698bb6f53d5c4ef08ee4e6a2dd269b9d488729ed4a171b7bd40ece3228cce5d305edd3673ed7773139bd133a14d5233a96cff7a9237142a77446e7125dba900e70681564f5a6acdc1285ae9e0feaf150d675e8d2d59dd315ad52931fec2973d1a5489c6698e29c5a508829797bd629a52665bcf9fdd32ed95c1d50217b5c18b67390f34befb8e78873a9b6b39ad285216328a2de3bef5b32a59db5ccec42a6b565aaf7dffba6e663d3972b211ea86b065f3cbccbc7b53890399a21a55f677f5863e4f670c337df667f58e3d6dc99dbef3dd5ff6bdf73ff82c65fbfaefc0d4fb5b868</data> + </image> + <image name="image3" > + <data format="XPM.GZ" length="802" >789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade65232325500210543251d2e25658564056503300071f540dc3430007371012a492a830156496538c094848922c9c2259134c099304914e3604c8424aa5e6449b0044216ca824ba2da8b4512218b4d122e8b55520fee5974072164511da487ea490c7f22cba249e20d3efc018f3fcae0d2702eb5d2106992b5d65c00b9a48974</data> + </image> + <image name="image4" > + <data format="XPM.GZ" length="1241" >789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade65232365200210543251d2e253d856405bffcbc54105b19c8563600020b03103711c4b530b08072f50880513524ab518681443435ca984ae08ae06a94114a10ac443435ca3043904d4c4453a38ca604ae11590d9a0ab80bd0d46078914c35c4d885a608871a547f61f81d5d117a1862018930e5b8d5c0950c741a1b1e6a6aadb90086a9d853</data> + </image> + <image name="image5" > + <data format="XPM.GZ" length="5598" >789ca5985973db480ec7dff3295cc15b6a0b2351a428d6d63ef83e255bbe647b6a1fd02465dd872d9f53f3dd076c005dc926ce6a32eed8553f37fadf7fa0c1a69cdfbe6cdc9cb537befcf6e97145ab61be910fe861e34bf1349dbefdfedffffcf1e97323dae07f51bdbe117dfed7a7cfddd546bed199cfca0ae888016afeab62e8796ef110ee545caf05be16ae5bfc6ee096e7b6e756983f51b6f53b81257ecfb8eee7e9b162f66af1c78125fe48987f23f3fb81657e691cd5bddecc7316d555efd058f7eb2867aa771058f4de8c55cffb6dd4a34cf5b68d357e681c6515634db81a7e3ef59c35cccf5560bf9ef6953389c77660af074f15c751e05c38a6d81f2ef9f3a848f4e9d658f2c36b635dbfa54cc2383556bd33e12492fc70df38f1f3f8ae4cc2745a711285fda7caa4f95e06967a2d8c63f27a8fc2a60fa4acfa980a371b898f0767dc6cf8fdbc9f84c27e4de124d2fabe186b3dee8c75ff1365dbef2db0ccef0987fd2f2a6632fd576552fd2b63d57b08ecd7d39d70b321fd0560acfb6d1a4b7e3050764de7d79f08a70de937ea7b7689e68f4de1e0776e2c7ab8abecb47eb170aa7ee822b0e89f1b4b7fd24dc529abe9794f02cbf99e2b3badc7a5b1ee97089b3e0e8d253f3c364e253e5576120ff7c63a9f7966d2e771d358e75bca4ef3bb0e2cf9758db5fe47c6b21eeb81bd3f07c2ad58ebd130d67e6a194b3cf97e62b2fa24c67a1f5d2aab3f8781a53e17c6eaa7082cfa3de156acf9d5034b7e3563f1eb96c6eaf7c0b815fbf8d2739e3aedefb1b1de9723618b77a49cebf946c6e20f5f8d251e753e8b5bb9e74c980a4afc7a7fbf66b1ed8fb7c67a9ec7c2ad5cfd74038bdfa6b1f6cbd458fd2e84b358efbb0363f5b71358fccd8c33596f9c4bfddcc458fac78d8cf5797b3296f5f82c4c49e6f5c9bf9fb23ce41307967e3935d6f36c0b67b1ce3f188b5f3757367f5363b98fdc38b0cc0f8cf5f90bf3ea97028bfe50981289777d63edcf81b1c4439897f3c52d615738cfe0df371c1deb7db265acf98d8d253f7a50d67a60c758cfcbf4cc7f2fb0f8bf1736bfae30d6f35f1a4b3ce6c6e2df95ca85f6f7dc58f3db0e5c783e14e6ebc533e87e963fbe0873f9fd3cc97c91693fd028b0d4e3c558f3eb0b9b5f972bab3fe78c353f3056bfabc0e2371636bfe4cf9b29d1e76b69acfdb863accfd33cb0dc2fa7c6e2179e03cb79ae940b7dffbf1b6bfd1363f53b12367f581a6b3d1bca56df6e60a9bfc6e765def4ecef6bc7eafaf9e8d558fbb7a15ce87d7263acf7ffbdb1e40f33e1e0cf29ebfea8eb6d7ff29f17f8f4137dfe51d8fa0117ca65ee3fbfe3bd705116b2de9f775e3af50313e1a229f1f0682cf1b052e6e1d9dfbf1cddd4fd2363cdcfef5fb05b7d1f0c944bed4f67ac9f5f27c265bf4c3d9f07eefb787f1f96695eaa1e0a174d7d7f81b1ee4f81a5fe75e552d9bf1fca7e617e9e8d556f33b0c4fbcf5ffdb44c956bc6a2d75dfd6c2020fd3ce2ff69a0c31c0b2cff91461fef71804374bfaa81231ce3044b9ce2ecd734380fc2392e70890ff888bfa6f184cff8c24e5ef10ddf71f3a37c3ed6c015afdec26dfeb983bbb887fb78f0f734380fe031c7437f3247788c27d8fe713e1f6a1076f014cfb08be7ac7481977885d75c951fe4f3630dcea3c3eb7b9cc70d6b9ce12d9fee26de610debeb69b0fb578cb89a0d8c399711e794609373d9c39455f2b53466d8c20c17809c45cc7a3c00f011081cffccff379fef35388f1d0428a0c401f459e58c3d45700f0003cee71d8678fc730d7430e2557d3c8331f7568c37308129cc7006733e9d262c6008cb6ff3f94ea3c72bc678ca3f1fb80a637884154c71c974c55d72c91a4feca4fdf553f8ad46554d8e9ee30a9eb1efab31611f2ff0ca346427bb9c11e114debe7e7ebed328318702e7f0ce9dbee47a1c724655b745b0c94ea6b0c55519f059b98f73d19a6cc30eecc21eecfb7100877004c770026de8e070bdfe805338832e9cc3055cc2955f7b0d3de8f0cfebb5356ee016eea0c6a30e11342086049a907aadcd35355a90111250f5e5288706bfdb4bea572a78b49e06ddd3a0d2807a2502110d6944639ad09466ebf9e8ae684e0bf5b1a4075ab28f11ffa1df678dc7f57cb0c68a9ee899355e7c2ddbf40a31bdb1c63bcdfe86c6803669cb9f4555c76b38a76dcee57d5d1f5c8f1d5af0b9745581bb029a5c8f3eedd21eed73b70ebe56fa91061dd061f05139e9d1116b1cfb9aee55c4fcf6330d5cd289d778a6b65fdd831dea702e256b9cf2b974a84367d4fd580347744e17744957acc13e7cfc095d538f356ed8cd2ddd518dea147da4c1956890ffcf295ed5e4c83b4a59f182b9455935e3b801ab791c7fa4e188d7a4bcbee66353feaef9df8852ca2f3e9ee3ef73840f359cabfec22979f4ddbd1bf018ba118f318f899bf298b9b95bb8e537cffe9ffffef4171c39a0bf</data> + </image> + <image name="image6" > + <data format="XPM.GZ" length="3742" >789c8d96c9521c490c86ef3c458775734cc8ddd5b5c6c41c303b180cc60b66620eaacc2c9aa5599b7562de7da45fc5180c8e98fa39f091522e4a49c9bbb783bdedcdc1db77735733991d864198c8e5e06dbc9e4eeffffceb8fbfe7de64d9407f466531c8defc36f76667360883adb3d364c013051ae2039f8147266359068f4dc6740a2e4db05f05d726f0253898c017c6a3cc04ffafce79aa3af0143c36c17e055caa0aacbf06aeb2203e5f09ae4d185f75ce472de6e7737063c2fcb57356b702fed673e32c473d4bcf3760198f02e69325706b022f3a676df0f567e05035d1ed273dc79883e7c1d1045e70ae2456d84fd9738a589f0b703261bc72ae25e17ee4b0e7d8f3b5733374e603e32c37c11ff36970db12f193f7e07c1c6bec87c6e0c604ff0e1c4db03f36cec7e3a6f4fd2e38e779eee7bd05e7e350fa7e4fc0455ee6b84fb9eab913bfdf1c5ce5758efba54fffb1e75302d726f8af3817a5f8f922584cf06fc0211f951ebfd0b30afe07ce4510dfdf1e38e665e9f9f1e01c32cf1fda06a73c2f7c7eac5f8c8b61eef582f315b909dc82f1c17e07dc1459e5f1c77d953abb787e0ab832611cf957366dd9c707f556762a3fcf8673ddd6d8afdc1957b909fe98af2a65d4c787c08d09e3c8bfaad504f378de83a309e35fc049d9d747bda19c7dbe8f602d88d6fd11af3a33c1ffde398e02ec69178c0b04bb7fa12be03e08e7ab4b895e2f74ec1ca2e73f6d811b2d37df1feaa9969082f71ff4a73a98c01f9cdb3678fde27eea58f7f9cdc8bfba33c11efda2199ac01bcead048fd72678a4e9e3f6a86f6d172acc87fc69f290f9386f3d72f478a1bf348509fea8b7a66c9b80fec1a8b7a66a53f47cc2fe9b5ae77346fe35ad09e761703081d12f9b68c2fc57ce6d0c1e6fe463934ce0efc63234c11ffd5b4a13c66f9cb53d79fded832bcd27f47f5aeb59055e744eb1df3fe2251aeee4e7453f9264c27aa847b44f7f4f909fda3efb7ae30c5c84b65f1fef435b9a608ff7a4ad4c981ffb6b6b13d8fda5edfb37eff4dcb65e2f787f5a7cb0f7fd0413ecf13eb49d09f6783ff07cf97d8ec0a3f8d8df516f483faf07c45b1f27e9f30ff989e9fdbe11ff1034fd3c9eebe068c238fa9f6677f2fb27ac1f475dd3f97da25fc6c204be755673ef3f8db3360c1f1f824b13c651df2877c44fd0df511efe5ea39f44318151cf9a4e2ab0af870d63fee4dc55fdfe109f880ff3fb788a8ff98df733762630fa471aa6febda2839e5b3f0fe1bef4f18bc9fb01fa7dca4ce0bb9e5b671ef69c3cff18f99cc626d853cf551f3fe453ca531bbdde979cbb2c793e207f536102a39fa5ca0446bf4279f97b89feaabb5181511f38bedf2ffa47373461bdcfe0dc8471d46387860fc6fbaad155c11ef7a5d953747ede69cf2a30fe3fd06c5121fe88572726f8a37f68720ffbfdadf7ac02fb7e82098c7e85ebf2fde37dea92098cf7acc367bc33fbff7a6ecfc4c22d078eaac41d1ff0e4d7f66a7df84293e71ecfec858f9ee8d1fef8a9c733fb139ef2299ff1395ff0255fc167c233befee1f1cc3ef10ddff21ddff303cfabe77bd584177891971e3d7ed8db4e7b2df30aaff29a7aac3ff9ebe4a9bdf2067fe04ddee28ffafb36eff027de558fcfbaab2ffc95bf3db5578b3dfecefb3ce411673c56ceb9e0b23f47a5fbac7fb26f889988742f2a129e504b81a246e0c8ec293cb7a7441d0b1dd0840ee9883486744253bea4533a7bd5fe9c2ed4feb29fff4aff32a36b8dd5e92fe6bfa15bddcf1dddd303cd93c6911668aa2b5cbc363f3c16799f9630fbb2d20aadd21aadeb3d547a8617f6f0d8a00fb4495bfadb47daa61dfa84f977e933c597f64f6e6c9fbed057fa467bf49df669c8bb34a2eca53d8d35576ef88e722aa8a48a6a6a448320a20fd36bf3eb7f407c2c89efb5500f6422877224c77222533915e6b397fbd117f54ccee54275295732936bb9915bb9937b797869ff34e7649ecfe4bd2ce81a8bbc2a4bb2fc5a3dfe2c59915559fb75fdfe8f7affe7f7b97f011cdd9635</data> + </image> + </images> +</ui> diff --git a/examples/activeqt/webbrowser/webaxwidget.h b/examples/activeqt/webbrowser/webaxwidget.h new file mode 100644 index 0000000..b03ce12 --- /dev/null +++ b/examples/activeqt/webbrowser/webaxwidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WEBAXWIDGET_H +#define WEBAXWIDGET_H + +#include <ActiveQt/QAxWidget> +#include "windows.h" + +class WebAxWidget : public QAxWidget +{ +public: + + WebAxWidget(QWidget* parent = 0, Qt::WindowFlags f = 0) + : QAxWidget(parent, f) + { + } +protected: + virtual bool translateKeyEvent(int message, int keycode) const + { + if (message >= WM_KEYFIRST && message <= WM_KEYLAST) + return true; + else + return QAxWidget::translateKeyEvent(message, keycode); + } + +}; + +#endif // WEBAXWIDGET_H diff --git a/examples/activeqt/webbrowser/webbrowser.pro b/examples/activeqt/webbrowser/webbrowser.pro new file mode 100644 index 0000000..32eac71 --- /dev/null +++ b/examples/activeqt/webbrowser/webbrowser.pro @@ -0,0 +1,17 @@ +TEMPLATE = app + +CONFIG += qaxcontainer + +QTDIR_build:REQUIRES = shared + +HEADERS = webaxwidget.h +SOURCES = main.cpp +FORMS = mainwindow.ui +wincewm*: FORMS = mainwindow_windowsmobile.ui + + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/webbrowser +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS webbrowser.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/webbrowser +INSTALLS += target sources diff --git a/examples/activeqt/wrapper/main.cpp b/examples/activeqt/wrapper/main.cpp new file mode 100644 index 0000000..49756d7 --- /dev/null +++ b/examples/activeqt/wrapper/main.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QAxFactory> +#include <QCheckBox> +#include <QRadioButton> +#include <QPushButton> +#include <QToolButton> +#include <QPixmap> + +/* XPM */ +static const char *fileopen[] = { +" 16 13 5 1", +". c #040404", +"# c #808304", +"a c None", +"b c #f3f704", +"c c #f3f7f3", +"aaaaaaaaa...aaaa", +"aaaaaaaa.aaa.a.a", +"aaaaaaaaaaaaa..a", +"a...aaaaaaaa...a", +".bcb.......aaaaa", +".cbcbcbcbc.aaaaa", +".bcbcbcbcb.aaaaa", +".cbcb...........", +".bcb.#########.a", +".cb.#########.aa", +".b.#########.aaa", +"..#########.aaaa", +"...........aaaaa" +}; + + +//! [0] +class ActiveQtFactory : public QAxFactory +{ +public: + ActiveQtFactory( const QUuid &lib, const QUuid &app ) + : QAxFactory( lib, app ) + {} + QStringList featureList() const + { + QStringList list; + list << "QCheckBox"; + list << "QRadioButton"; + list << "QPushButton"; + list << "QToolButton"; + return list; + } + QObject *createObject(const QString &key) + { + if ( key == "QCheckBox" ) + return new QCheckBox(0); + if ( key == "QRadioButton" ) + return new QRadioButton(0); + if ( key == "QPushButton" ) + return new QPushButton(0 ); + if ( key == "QToolButton" ) { + QToolButton *tb = new QToolButton(0); +// tb->setIcon( QPixmap(fileopen) ); + return tb; + } + + return 0; + } + const QMetaObject *metaObject( const QString &key ) const + { + if ( key == "QCheckBox" ) + return &QCheckBox::staticMetaObject; + if ( key == "QRadioButton" ) + return &QRadioButton::staticMetaObject; + if ( key == "QPushButton" ) + return &QPushButton::staticMetaObject; + if ( key == "QToolButton" ) + return &QToolButton::staticMetaObject; + + return 0; + } + QUuid classID( const QString &key ) const + { + if ( key == "QCheckBox" ) + return "{6E795DE9-872D-43CF-A831-496EF9D86C68}"; + if ( key == "QRadioButton" ) + return "{AFCF78C8-446C-409A-93B3-BA2959039189}"; + if ( key == "QPushButton" ) + return "{2B262458-A4B6-468B-B7D4-CF5FEE0A7092}"; + if ( key == "QToolButton" ) + return "{7c0ffe7a-60c3-4666-bde2-5cf2b54390a1}"; + + return QUuid(); + } + QUuid interfaceID( const QString &key ) const + { + if ( key == "QCheckBox" ) + return "{4FD39DD7-2DE0-43C1-A8C2-27C51A052810}"; + if ( key == "QRadioButton" ) + return "{7CC8AE30-206C-48A3-A009-B0A088026C2F}"; + if ( key == "QPushButton" ) + return "{06831CC9-59B6-436A-9578-6D53E5AD03D3}"; + if ( key == "QToolButton" ) + return "{6726080f-d63d-4950-a366-9bf33e5cdf84}"; + + return QUuid(); + } + QUuid eventsID( const QString &key ) const + { + if ( key == "QCheckBox" ) + return "{FDB6FFBE-56A3-4E90-8F4D-198488418B3A}"; + if ( key == "QRadioButton" ) + return "{73EE4860-684C-4A66-BF63-9B9EFFA0CBE5}"; + if ( key == "QPushButton" ) + return "{3CC3F17F-EA59-4B58-BBD3-842D467131DD}"; + if ( key == "QToolButton" ) + return "{f4d421fd-4ead-4fd9-8a25-440766939639}"; + + return QUuid(); + } +}; +//! [0] //! [1] + +QAXFACTORY_EXPORT( ActiveQtFactory, "{3B756301-0075-4E40-8BE8-5A81DE2426B7}", "{AB068077-4924-406a-BBAF-42D91C8727DD}" ) +//! [1] diff --git a/examples/activeqt/wrapper/wrapper.inf b/examples/activeqt/wrapper/wrapper.inf new file mode 100644 index 0000000..fc17a3d --- /dev/null +++ b/examples/activeqt/wrapper/wrapper.inf @@ -0,0 +1,9 @@ +[version] + signature="$CHICAGO$" + AdvancedINF=2.0 + [Add.Code] + wrapperax.dll=wrapperax.dll + [wrapperax.dll] + file-win32-x86=thiscab + clsid={23F5012A-7333-43D3-BCA8-836AABC61B4A} + RegisterServer=yes diff --git a/examples/activeqt/wrapper/wrapper.pro b/examples/activeqt/wrapper/wrapper.pro new file mode 100644 index 0000000..4eb6baf --- /dev/null +++ b/examples/activeqt/wrapper/wrapper.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +TARGET = wrapperax + +CONFIG += qt warn_off qaxserver dll +contains(CONFIG, static):DEFINES += QT_NODLL + +SOURCES = main.cpp +RC_FILE = wrapperax.rc +DEF_FILE = $$QT_SOURCE_TREE/src/activeqt/control/qaxserver.def + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/activeqt/wrapper +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS wrapper.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/activeqt/wrapper +INSTALLS += target sources diff --git a/examples/activeqt/wrapper/wrapperax.rc b/examples/activeqt/wrapper/wrapperax.rc new file mode 100644 index 0000000..0ccf606 --- /dev/null +++ b/examples/activeqt/wrapper/wrapperax.rc @@ -0,0 +1,32 @@ +#include "winver.h" + +1 TYPELIB "wrapperax.rc" +1 ICON DISCARDABLE "..\\..\\..\\src\\activeqt\\control\\qaxserver.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL + FILEOS 0x00040000L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Wrapper Example (ActiveQt)" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "wrapperax.dll" + VALUE "OriginalFilename", "wrapperax.dll" + VALUE "ProductName", "Wrapper Example (ActiveQt)" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/examples/examples.pro b/examples/examples.pro new file mode 100644 index 0000000..4f16fa0 --- /dev/null +++ b/examples/examples.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += activeqt diff --git a/src/activeqt/activeqt.pro b/src/activeqt/activeqt.pro new file mode 100644 index 0000000..0948ea0 --- /dev/null +++ b/src/activeqt/activeqt.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +CONFIG += ordered +SUBDIRS = container +!wince*: SUBDIRS += control diff --git a/src/activeqt/container/container.pro b/src/activeqt/container/container.pro new file mode 100644 index 0000000..4c9b3a8 --- /dev/null +++ b/src/activeqt/container/container.pro @@ -0,0 +1,41 @@ +TEMPLATE = lib + +TARGET = ActiveQt +CONFIG += qt_install_headers +SYNCQT.HEADER_FILES = qaxbase.h qaxobject.h qaxscript.h qaxselect.h qaxwidget.h +SYNCQT.HEADER_CLASSES = ../../../include/ActiveQt/QAxBase ../../../include/ActiveQt/QAxObject ../../../include/ActiveQt/QAxScriptEngine ../../../include/ActiveQt/QAxScript ../../../include/ActiveQt/QAxScriptManager ../../../include/ActiveQt/QAxSelect ../../../include/ActiveQt/QAxWidget +include(../../qt_install.pri) + +TARGET = QAxContainer + +!debug_and_release|build_pass { + CONFIG(debug, debug|release) { + TARGET = $$member(TARGET, 0)d + } +} + +CONFIG += qt warn_on staticlib +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/lib + +LIBS += -lole32 -loleaut32 +!wince*:LIBS += -luser32 -lgdi32 -ladvapi32 +win32-g++*:LIBS += -luuid + +HEADERS = ../control/qaxaggregated.h \ + qaxbase.h \ + qaxwidget.h \ + qaxobject.h \ + qaxscript.h \ + qaxselect.h \ + ../shared/qaxtypes.h + +SOURCES = qaxbase.cpp \ + qaxdump.cpp \ + qaxwidget.cpp \ + qaxobject.cpp \ + qaxscript.cpp \ + qaxscriptwrapper.cpp \ + qaxselect.cpp \ + ../shared/qaxtypes.cpp + +FORMS = qaxselect.ui diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp new file mode 100644 index 0000000..aa51925 --- /dev/null +++ b/src/activeqt/container/qaxbase.cpp @@ -0,0 +1,4472 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//#define QAX_NO_CLASSINFO + +#define QT_CHECK_STATE + +#include "qaxobject.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qfile.h> +#include <qwidget.h> + +#include <quuid.h> +#include <qhash.h> +#include <qset.h> +#include <qpair.h> +#include <qmetaobject.h> +#include <qsettings.h> + +#ifndef QT_NO_THREAD +# include <qmutex.h> +#endif + +#include <qt_windows.h> +#include <ocidl.h> +#include <ctype.h> + +#include "../shared/qaxtypes.h" + +QT_BEGIN_NAMESPACE + +/* + \internal + \class QAxMetaObject + + \brief The QAxMetaObject class stores extended information +*/ +struct QAxMetaObject : public QMetaObject +{ + QAxMetaObject() + { + d.data = 0; + d.stringdata = 0; + } + ~QAxMetaObject() + { + delete [] (int*)d.data; + delete [] (char*)d.stringdata; + } + + int numParameter(const QByteArray &prototype); + QByteArray paramType(const QByteArray &signature, int index, bool *out = 0); + QByteArray propertyType(const QByteArray &propertyName); + void parsePrototype(const QByteArray &prototype); + DISPID dispIDofName(const QByteArray &name, IDispatch *disp); + +private: + friend class MetaObjectGenerator; + // save information about QAxEventSink connections, and connect when found in cache + QList<QUuid> connectionInterfaces; + // DISPID -> signal name + QMap< QUuid, QMap<DISPID, QByteArray> > sigs; + // DISPID -> property changed signal name + QMap< QUuid, QMap<DISPID, QByteArray> > propsigs; + // DISPID -> property name + QMap< QUuid, QMap<DISPID, QByteArray> > props; + + // Prototype -> member info + QHash<QByteArray, QList<QByteArray> > memberInfo; + QMap<QByteArray, QByteArray> realPrototype; + + // DISPID cache + QHash<QByteArray, DISPID> dispIDs; +}; + +void QAxMetaObject::parsePrototype(const QByteArray &prototype) +{ + QByteArray realProto = realPrototype.value(prototype, prototype); + QByteArray parameters = realProto.mid(realProto.indexOf('(') + 1); + parameters.truncate(parameters.length() - 1); + + if (parameters.isEmpty()) { + memberInfo.insert(prototype, QList<QByteArray>()); + } else { + QList<QByteArray> plist = parameters.split(','); + memberInfo.insert(prototype, plist); + } +} + +inline QByteArray QAxMetaObject::propertyType(const QByteArray &propertyName) +{ + return realPrototype.value(propertyName); +} + +int QAxMetaObject::numParameter(const QByteArray &prototype) +{ + if (!memberInfo.contains(prototype)) + parsePrototype(prototype); + + return memberInfo.value(prototype).count(); +} + +QByteArray QAxMetaObject::paramType(const QByteArray &prototype, int index, bool *out) +{ + if (!memberInfo.contains(prototype)) + parsePrototype(prototype); + + if (out) + *out = false; + + QList<QByteArray> plist = memberInfo.value(prototype); + if (index > plist.count() - 1) + return QByteArray(); + + QByteArray param(plist.at(index)); + if (param.isEmpty()) + return QByteArray(); + + bool byRef = param.endsWith('&') || param.endsWith("**"); + if (byRef) { + param.truncate(param.length() - 1); + if (out) + *out = true; + } + + return param; +} + +inline DISPID QAxMetaObject::dispIDofName(const QByteArray &name, IDispatch *disp) +{ + DISPID dispid = dispIDs.value(name, DISPID_UNKNOWN); + if (dispid == DISPID_UNKNOWN) { + // get the Dispatch ID from the object + QString unicodeName = QLatin1String(name); + OLECHAR *names = (wchar_t*)unicodeName.utf16(); + disp->GetIDsOfNames(IID_NULL, &names, 1, LOCALE_USER_DEFAULT, &dispid); + if (dispid != DISPID_UNKNOWN) + dispIDs.insert(name, dispid); + } + return dispid; +} + + +static QHash<QString, QAxMetaObject*> mo_cache; +static QHash<QUuid, QMap<QByteArray, QList<QPair<QByteArray, int> > > > enum_cache; +static int mo_cache_ref = 0; +static QMutex cache_mutex; + + +static const char *const type_conversion[][2] = +{ + { "float", "double"}, + { "short", "int"}, + { "char", "int"}, + { "QList<int>", "QVariantList" }, + { "QList<uint>", "QVariantList" }, + { "QList<double>", "QVariantList" }, + { "QList<bool>", "QVariantList" }, + { "QList<QDateTime>", "QVariantList" }, + { "QList<qlonglong>", "QVariantList" }, + { 0, 0 } +}; + +/* + \internal + \class QAxEventSink + + \brief The QAxEventSink class implements the event sink for all + IConnectionPoints implemented in the COM object. +*/ + +class QAxEventSink : public IDispatch, public IPropertyNotifySink +{ +public: + QAxEventSink(QAxBase *com) + : cpoint(0), ciid(IID_NULL), combase(com), ref(1) + {} + virtual ~QAxEventSink() + { + Q_ASSERT(!cpoint); + } + + QUuid connectionInterface() const + { + return ciid; + } + QMap<DISPID, QByteArray> signalMap() const + { + return sigs; + } + QMap<DISPID, QByteArray> propertyMap() const + { + return props; + } + QMap<DISPID, QByteArray> propSignalMap() const + { + return propsigs; + } + + // add a connection + void advise(IConnectionPoint *cp, IID iid) + { + cpoint = cp; + cpoint->AddRef(); + ciid = iid; + cpoint->Advise((IUnknown*)(IDispatch*)this, &cookie); + } + + // disconnect from all connection points + void unadvise() + { + combase = 0; + if (cpoint) { + cpoint->Unadvise(cookie); + cpoint->Release(); + cpoint = 0; + } + } + + void addSignal(DISPID memid, const char *name) + { + QByteArray signalname = name; + int pi = signalname.indexOf('('); + int i = 0; + while (type_conversion[i][0]) { + int ti = pi; + int len = int(strlen(type_conversion[i][0])); + while ((ti = signalname.indexOf(type_conversion[i][0], ti)) != -1) + signalname.replace(ti, len, type_conversion[i][1]); + ++i; + } + + sigs.insert(memid, signalname); + QMap<DISPID,QByteArray>::ConstIterator it; + DISPID id = -1; + for (it = propsigs.constBegin(); it!= propsigs.constEnd(); ++it) { + if (it.value() == signalname) { + id = it.key(); + break; + } + } + if (id != -1) + propsigs.remove(id); + } + void addProperty(DISPID propid, const char *name, const char *signal) + { + props.insert(propid, name); + propsigs.insert(propid, signal); + } + + // IUnknown + unsigned long __stdcall AddRef() + { + return ref++; + } + unsigned long __stdcall Release() + { + if (!--ref) { + delete this; + return 0; + } + return ref; + } + HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject) + { + *ppvObject = 0; + if (riid == IID_IUnknown) + *ppvObject = (IUnknown*)(IDispatch*)this; + else if (riid == IID_IDispatch) + *ppvObject = (IDispatch*)this; + else if (riid == IID_IPropertyNotifySink) + *ppvObject = (IPropertyNotifySink*)this; + else if (ciid == riid) + *ppvObject = (IDispatch*)this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; + } + + // IDispatch + HRESULT __stdcall GetTypeInfoCount(unsigned int *) { return E_NOTIMPL; } + HRESULT __stdcall GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_NOTIMPL; } + HRESULT __stdcall GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *) { return E_NOTIMPL; } + + HRESULT __stdcall Invoke(DISPID dispIdMember, + REFIID riid, + LCID, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT*, + EXCEPINFO*, + UINT*) + { + // verify input + if (riid != IID_NULL) + return DISP_E_UNKNOWNINTERFACE; + if (!(wFlags & DISPATCH_METHOD)) + return DISP_E_MEMBERNOTFOUND; + if (!combase) + return E_UNEXPECTED; + + QByteArray signame = sigs.value(dispIdMember); + if (signame.isEmpty()) + return DISP_E_MEMBERNOTFOUND; + + QObject *qobject = combase->qObject(); + if (qobject->signalsBlocked()) + return S_OK; + + QAxMetaObject *axmeta = combase->internalMetaObject(); + const QMetaObject *meta = combase->metaObject(); + + int index = -1; + // emit the generic signal "as is" + if (signalHasReceivers(qobject, "signal(QString,int,void*)")) { + index = meta->indexOfSignal("signal(QString,int,void*)"); + Q_ASSERT(index != -1); + + QString nameString = QLatin1String(signame); + void *argv[] = {0, &nameString, &pDispParams->cArgs, &pDispParams->rgvarg}; + combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv); + } + + HRESULT hres = S_OK; + + // get the signal information from the metaobject + index = -1; + if (signalHasReceivers(qobject, signame)) { + index = meta->indexOfSignal(signame); + Q_ASSERT(index != -1); + const QMetaMethod signal = meta->method(index); + Q_ASSERT(signal.methodType() == QMetaMethod::Signal); + Q_ASSERT(signame == signal.signature()); + // verify parameter count + int pcount = axmeta->numParameter(signame); + int argcount = pDispParams->cArgs; + if (pcount > argcount) + return DISP_E_PARAMNOTOPTIONAL; + else if (pcount < argcount) + return DISP_E_BADPARAMCOUNT; + + // setup parameters (no return values in signals) + bool ok = true; + void *static_argv[QAX_NUM_PARAMS + 1]; + void *static_argv_pointer[QAX_NUM_PARAMS + 1]; + QVariant static_varp[QAX_NUM_PARAMS + 1]; + + void **argv = 0; + void **argv_pointer = 0; // in case we need an additional level of indirection + QVariant *varp = 0; + + if (pcount) { + if (pcount <= QAX_NUM_PARAMS) { + argv = static_argv; + argv_pointer = static_argv_pointer; + varp = static_varp; + } else { + argv = new void*[pcount + 1]; + argv_pointer = new void*[pcount + 1]; + varp = new QVariant[pcount + 1]; + } + + argv[0] = 0; + argv_pointer[0] = 0; + } + + int p; + for (p = 0; p < pcount && ok; ++p) { + // map the VARIANT to the void* + QByteArray ptype = axmeta->paramType(signame, p); + varp[p + 1] = VARIANTToQVariant(pDispParams->rgvarg[pcount - p - 1], ptype); + argv_pointer[p + 1] = 0; + if (varp[p + 1].isValid()) { + if (varp[p + 1].type() == QVariant::UserType) { + argv[p + 1] = varp[p + 1].data(); + } else if (ptype == "QVariant") { + argv[p + 1] = varp + p + 1; + } else { + argv[p + 1] = const_cast<void*>(varp[p + 1].constData()); + if (ptype.endsWith('*')) { + argv_pointer[p + 1] = argv[p + 1]; + argv[p + 1] = argv_pointer + p + 1; + } + } + } else if (ptype == "QVariant") { + argv[p + 1] = varp + p + 1; + } else { + ok = false; + } + } + + if (ok) { + // emit the generated signal if everything went well + combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv); + // update the VARIANT for references and free memory + for (p = 0; p < pcount; ++p) { + bool out; + QByteArray ptype = axmeta->paramType(signame, p, &out); + if (out) { + if (!QVariantToVARIANT(varp[p + 1], pDispParams->rgvarg[pcount - p - 1], ptype, out)) + ok = false; + } + } + } + + if (argv != static_argv) { + delete [] argv; + delete [] argv_pointer; + delete [] varp; + } + hres = ok ? S_OK : (ok ? DISP_E_MEMBERNOTFOUND : DISP_E_TYPEMISMATCH); + } + + return hres; + } + + QByteArray findProperty(DISPID dispID); + + // IPropertyNotifySink + HRESULT __stdcall OnChanged(DISPID dispID) + { + // verify input + if (dispID == DISPID_UNKNOWN || !combase) + return S_OK; + + const QMetaObject *meta = combase->metaObject(); + if (!meta) + return S_OK; + + QByteArray propname(findProperty(dispID)); + if (propname.isEmpty()) + return S_OK; + + QObject *qobject = combase->qObject(); + if (qobject->signalsBlocked()) + return S_OK; + + // emit the generic signal + int index = meta->indexOfSignal("propertyChanged(QString)"); + if (index != -1) { + QString propnameString = QString::fromLatin1(propname); + void *argv[] = {0, &propnameString}; + combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv); + } + + QByteArray signame = propsigs.value(dispID); + if (signame.isEmpty()) + return S_OK; + + index = meta->indexOfSignal(signame); + if (index == -1) // bindable but not marked as bindable in typelib + return S_OK; + + // get the signal information from the metaobject + if (signalHasReceivers(qobject, signame)) { + index = meta->indexOfSignal(signame); + Q_ASSERT(index != -1); + // setup parameters + QVariant var = qobject->property(propname); + if (!var.isValid()) + return S_OK; + + const QMetaProperty metaProp = meta->property(meta->indexOfProperty(propname)); + void *argv[] = {0, var.data()}; + if (metaProp.type() == QVariant::LastType) + argv[1] = &var; + + // emit the "changed" signal + combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv); + } + return S_OK; + } + HRESULT __stdcall OnRequestEdit(DISPID dispID) + { + if (dispID == DISPID_UNKNOWN || !combase) + return S_OK; + + QByteArray propname(findProperty(dispID)); + if (propname.isEmpty()) + return S_OK; + + return combase->propertyWritable(propname) ? S_OK : S_FALSE; + } + + static bool signalHasReceivers(QObject *qobject, const char *signalName) + { + Q_ASSERT(qobject); + return ((QAxObject*)qobject)->receivers(QByteArray::number(QSIGNAL_CODE) + signalName); + } + + IConnectionPoint *cpoint; + IID ciid; + ULONG cookie; + + QMap<DISPID, QByteArray> sigs; + QMap<DISPID, QByteArray> propsigs; + QMap<DISPID, QByteArray> props; + + QAxBase *combase; + long ref; +}; + +/* + \internal + \class QAxBasePrivate +*/ + +class QAxBasePrivate +{ +public: + QAxBasePrivate() + : useEventSink(true), useMetaObject(true), useClassInfo(true), + cachedMetaObject(false), initialized(false), tryCache(false), + ptr(0), disp(0), metaobj(0) + { + // protect initialization + QMutexLocker locker(&cache_mutex); + mo_cache_ref++; + + qRegisterMetaType<IUnknown*>("IUnknown*", &ptr); + qRegisterMetaType<IDispatch*>("IDispatch*", &disp); + } + + ~QAxBasePrivate() + { + Q_ASSERT(!ptr); + Q_ASSERT(!disp); + + // protect cleanup + QMutexLocker locker(&cache_mutex); + if (!--mo_cache_ref) { + qDeleteAll(mo_cache); + mo_cache.clear(); + } + + CoFreeUnusedLibraries(); + } + + inline IDispatch *dispatch() const + { + if (disp) + return disp; + + if (ptr) + ptr->QueryInterface(IID_IDispatch, (void**)&disp); + return disp; + } + + QString ctrl; + + QHash<QUuid, QAxEventSink*> eventSink; + uint useEventSink :1; + uint useMetaObject :1; + uint useClassInfo :1; + uint cachedMetaObject :1; + uint initialized :1; + uint tryCache :1; + + IUnknown *ptr; + mutable IDispatch *disp; + + QMap<QByteArray, bool> propWritable; + + inline QAxMetaObject *metaObject() + { + if (!metaobj) + metaobj = new QAxMetaObject; + return metaobj; + } + + mutable QMap<QString, LONG> verbs; + + QAxMetaObject *metaobj; +}; + + +QByteArray QAxEventSink::findProperty(DISPID dispID) +{ + // look up in cache, and fall back to + // type info for precompiled metaobjects + QByteArray propname(props.value(dispID)); + + if (!propname.isEmpty()) + return propname; + + IDispatch *dispatch = combase->d->dispatch(); + ITypeInfo *typeinfo = 0; + if (dispatch) + dispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo); + if (!typeinfo) + return propname; + + BSTR names; + UINT cNames; + typeinfo->GetNames(dispID, &names, 1, &cNames); + if (cNames) { + propname = QString::fromWCharArray(names).toLatin1(); + SysFreeString(names); + } + typeinfo->Release(); + + QByteArray propsignal(propname + "Changed("); + const QMetaObject *mo = combase->metaObject(); + int index = mo->indexOfProperty(propname); + const QMetaProperty prop = mo->property(index); + propsignal += prop.typeName(); + propsignal += ')'; + addProperty(dispID, propname, propsignal); + + return propname; +} + +/*! + \class QAxBase + \brief The QAxBase class is an abstract class that provides an API + to initialize and access a COM object. + + \inmodule QAxContainer + + QAxBase is an abstract class that cannot be used directly, and is + instantiated through the subclasses QAxObject and QAxWidget. This + class provides the API to access the COM object directly + through its IUnknown implementation. If the COM object implements + the IDispatch interface, the properties and methods of that object + become available as Qt properties and slots. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 0 + + Properties exposed by the object's IDispatch implementation can + be read and written through the property system provided by the + Qt Object Model (both subclasses are QObjects, so you can use + QObject::setProperty() and QObject::property()). Properties with + multiple parameters are not supported. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 1 + + Write-functions for properties and other methods exposed by the + object's IDispatch implementation can be called directly using + dynamicCall(), or indirectly as slots connected to a signal. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 2 + + Outgoing events supported by the COM object are emitted as + standard Qt signals. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 3 + + QAxBase transparently converts between COM data types and the + equivalent Qt data types. Some COM types have no equivalent Qt data structure. + + Supported COM datatypes are listed in the first column of following table. + The second column is the Qt type that can be used with the QObject property + functions. The third column is the Qt type that is used in the prototype of + generated signals and slots for in-parameters, and the last column is the Qt + type that is used in the prototype of signals and slots for out-parameters. + \table + \header + \i COM type + \i Qt property + \i in-parameter + \i out-parameter + \row + \i VARIANT_BOOL + \i bool + \i bool + \i bool& + \row + \i BSTR + \i QString + \i const QString& + \i QString& + \row + \i char, short, int, long + \i int + \i int + \i int& + \row + \i uchar, ushort, uint, ulong + \i uint + \i uint + \i uint& + \row + \i float, double + \i double + \i double + \i double& + \row + \i DATE + \i QDateTime + \i const QDateTime& + \i QDateTime& + \row + \i CY + \i qlonglong + \i qlonglong + \i qlonglong& + \row + \i OLE_COLOR + \i QColor + \i const QColor& + \i QColor& + \row + \i SAFEARRAY(VARIANT) + \i QList\<QVariant\> + \i const QList\<QVariant\>& + \i QList\<QVariant\>& + \row + \i SAFEARRAY(int), SAFEARRAY(double), SAFEARRAY(Date) + \i QList\<QVariant\> + \i const QList\<QVariant\>& + \i QList\<QVariant\>& + \row + \i SAFEARRAY(BYTE) + \i QByteArray + \i const QByteArray& + \i QByteArray& + \row + \i SAFEARRAY(BSTR) + \i QStringList + \i const QStringList& + \i QStringList& + \row + \i VARIANT + \i type-dependent + \i const QVariant& + \i QVariant& + \row + \i IFontDisp* + \i QFont + \i const QFont& + \i QFont& + \row + \i IPictureDisp* + \i QPixmap + \i const QPixmap& + \i QPixmap& + \row + \i IDispatch* + \i QAxObject* + \i \c QAxBase::asVariant() + \i QAxObject* (return value) + \row + \i IUnknown* + \i QAxObject* + \i \c QAxBase::asVariant() + \i QAxObject* (return value) + \row + \i SCODE, DECIMAL + \i \e unsupported + \i \e unsupported + \i \e unsupported + \row + \i VARIANT* (Since Qt 4.5) + \i \e unsupported + \i \e QVariant& + \i \e QVariant& + \endtable + + Supported are also enumerations, and typedefs to supported types. + + To call the methods of a COM interface described by the following IDL + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 4 + + use the QAxBase API like this: + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 5 + + Note that the QList the object should fill has to be provided as an + element in the parameter list of \l{QVariant}s. + + If you need to access properties or pass parameters of + unsupported datatypes you must access the COM object directly + through its \c IDispatch implementation or other interfaces. + Those interfaces can be retrieved through queryInterface(). + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 6 + + To get the definition of the COM interfaces you will have to use the header + files provided with the component you want to use. Some compilers can also + import type libraries using the #import compiler directive. See the component + documentation to find out which type libraries you have to import, and how to use + them. + + If you need to react to events that pass parameters of unsupported + datatypes you can use the generic signal that delivers the event + data as provided by the COM event. + + \sa QAxObject, QAxWidget, QAxScript, {ActiveQt Framework} +*/ + +/*! + \typedef QAxBase::PropertyBag + + A QMap<QString,QVariant> that can store properties as name:value pairs. +*/ + +/*! + Creates a QAxBase object that wraps the COM object \a iface. If \a + iface is 0 (the default), use setControl() to instantiate a COM + object. +*/ +QAxBase::QAxBase(IUnknown *iface) +{ + d = new QAxBasePrivate(); + d->ptr = iface; + if (d->ptr) { + d->ptr->AddRef(); + d->initialized = true; + } +#if defined(Q_OS_WINCE) + CoInitializeEx(0, COINIT_MULTITHREADED); +#endif +} + +/*! + Shuts down the COM object and destroys the QAxBase object. + + \sa clear() +*/ +QAxBase::~QAxBase() +{ +#if defined(Q_OS_WINCE) + CoUninitialize(); +#endif + + clear(); + + delete d; + d = 0; +} + +/*! + \internal + + Used by subclasses generated with dumpcpp to balance reference count. +*/ +void QAxBase::internalRelease() +{ + if (d->ptr) + d->ptr->Release(); +} + +/*! + \internal + + Used by subclasses generated with dumpcpp to implement cast-operators. +*/ +void QAxBase::initializeFrom(QAxBase *that) +{ + if (d->ptr) + return; + + d->ptr = that->d->ptr; + if (d->ptr) { + d->ptr->AddRef(); + d->initialized = true; + } +} + + +QAxMetaObject *QAxBase::internalMetaObject() const +{ + return d->metaObject(); +} + +/*! + \property QAxBase::control + \brief the name of the COM object wrapped by this QAxBase object. + + Setting this property initializes the COM object. Any COM object + previously set is shut down. + + The most efficient way to set this property is by using the + registered component's UUID, e.g. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 7 + + The second fastest way is to use the registered control's class + name (with or without version number), e.g. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 8 + + The slowest, but easiest way to use is to use the control's full + name, e.g. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 9 + + It is also possible to initialize the object from a file, e.g. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 10 + + If the component's UUID is used the following patterns can be used + to initialize the control on a remote machine, to initialize a + licensed control or to connect to a running object: + \list + \i To initialize the control on a different machine use the following + pattern: + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 11 + + \i To initialize a licensed control use the following pattern: + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 12 + + \i To connect to an already running object use the following pattern: + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 13 + + \endlist + The first two patterns can be combined, e.g. to initialize a licensed + control on a remote machine: + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 14 + + The control's read function always returns the control's UUID, if provided including the license + key, and the name of the server, but not including the username, the domain or the password. +*/ +bool QAxBase::setControl(const QString &c) +{ + if (c.toLower() == d->ctrl.toLower()) + return !d->ctrl.isEmpty(); + + QString search = c; + // don't waste time for DCOM requests + int dcomIDIndex = search.indexOf(QLatin1String("/{")); + if ((dcomIDIndex == -1 || dcomIDIndex != search.length()-39) && !search.endsWith(QLatin1String("}&"))) { + QUuid uuid(search); + if (uuid.isNull()) { + CLSID clsid; + HRESULT res = CLSIDFromProgID((wchar_t*)c.utf16(), &clsid); + if (res == S_OK) + search = QUuid(clsid).toString(); + else { + QSettings controls(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes\\"), QSettings::NativeFormat); + search = controls.value(c + QLatin1String("/CLSID/Default")).toString(); + if (search.isEmpty()) { + controls.beginGroup(QLatin1String("/CLSID")); + QStringList clsids = controls.childGroups(); + for (QStringList::Iterator it = clsids.begin(); it != clsids.end(); ++it) { + QString clsid = *it; + QString name = controls.value(clsid + QLatin1String("/Default")).toString(); + if (name == c) { + search = clsid; + break; + } + } + controls.endGroup(); + } + } + } + if (search.isEmpty()) + search = c; + } + + if (search.toLower() == d->ctrl.toLower()) + return !d->ctrl.isEmpty(); + + clear(); + d->ctrl = search; + + d->tryCache = true; + if (!initialize(&d->ptr)) + d->initialized = true; + if (isNull()) { + qWarning("QAxBase::setControl: requested control %s could not be instantiated", c.toLatin1().data()); + clear(); + return false; + } + return true; +} + +QString QAxBase::control() const +{ + return d->ctrl; +} + +/*! + Disables the event sink implementation for this ActiveX container. + If you don't intend to listen to the ActiveX control's events use + this function to speed up the meta object generation. + + Some ActiveX controls might be unstable when connected to an event + sink. To get OLE events you must use standard COM methods to + register your own event sink. Use queryInterface() to get access + to the raw COM object. + + Note that this function should be called immediately after + construction of the object. +*/ +void QAxBase::disableEventSink() +{ + d->useEventSink = false; +} + +/*! + Disables the meta object generation for this ActiveX container. + This also disables the event sink and class info generation. If + you don't intend to use the Qt meta object implementation call + this function to speed up instantiation of the control. You will + still be able to call the object through \l dynamicCall(), but + signals, slots and properties will not be available with QObject + APIs. + + Some ActiveX controls might be unstable when used with OLE + automation. Use standard COM methods to use those controls through + the COM interfaces provided by queryInterface(). + + Note that this function must be called immediately after + construction of the object. +*/ +void QAxBase::disableMetaObject() +{ + d->useMetaObject = false; + d->useEventSink = false; + d->useClassInfo = false; +} + +/*! + Disables the class info generation for this ActiveX container. If + you don't require any class information about the ActiveX control + use this function to speed up the meta object generation. + + Note that this function must be called immediately after + construction of the object +*/ +void QAxBase::disableClassInfo() +{ + d->useClassInfo = false; +} + +/*! + Disconnects and destroys the COM object. + + If you reimplement this function you must also reimplement the + destructor to call clear(), and call this implementation at the + end of your clear() function. +*/ +void QAxBase::clear() +{ + QHash<QUuid, QAxEventSink*>::Iterator it = d->eventSink.begin(); + while (it != d->eventSink.end()) { + QAxEventSink *eventSink = it.value(); + ++it; + if (eventSink) { + eventSink->unadvise(); + eventSink->Release(); + } + } + d->eventSink.clear(); + if (d->disp) { + d->disp->Release(); + d->disp = 0; + } + if (d->ptr) { + d->ptr->Release(); + d->ptr = 0; + d->initialized = false; + } + + d->ctrl.clear(); + + if (!d->cachedMetaObject) + delete d->metaobj; + d->metaobj = 0; +} + +/*! + \since 4.1 + + Returns the list of verbs that the COM object can execute. If + the object does not implement IOleObject, or does not support + any verbs, then this function returns an empty stringlist. + + Note that the OLE default verbs (OLEIVERB_SHOW etc) are not + included in the list. +*/ +QStringList QAxBase::verbs() const +{ + if (!d->ptr) + return QStringList(); + + if (d->verbs.isEmpty()) { + IOleObject *ole = 0; + d->ptr->QueryInterface(IID_IOleObject, (void**)&ole); + if (ole) { + IEnumOLEVERB *enumVerbs = 0; + ole->EnumVerbs(&enumVerbs); + if (enumVerbs) { + enumVerbs->Reset(); + ULONG c; + OLEVERB verb; + while (enumVerbs->Next(1, &verb, &c) == S_OK) { + if (!verb.lpszVerbName) + continue; + QString verbName = QString::fromWCharArray(verb.lpszVerbName); + if (!verbName.isEmpty()) + d->verbs.insert(verbName, verb.lVerb); + } + enumVerbs->Release(); + } + ole->Release(); + } + } + + return d->verbs.keys(); +} + +/*! + \internal +*/ + +long QAxBase::indexOfVerb(const QString &verb) const +{ + return d->verbs.value(verb); +} + +/*! + This virtual function is called by setControl() and creates the + requested COM object. \a ptr is set to the object's IUnknown + implementation. The function returns true if the object + initialization succeeded; otherwise the function returns false. + + The default implementation interprets the string returned by + control(), and calls initializeRemote(), initializeLicensed() + or initializeActive() if the string matches the respective + patterns. If control() is the name of an existing file, + initializeFromFile() is called. If no pattern is matched, or + if remote or licensed initialization fails, CoCreateInstance + is used directly to create the object. + + See the \l control property documentation for details about + supported patterns. + + The interface returned in \a ptr must be referenced exactly once + when this function returns. The interface provided by e.g. + CoCreateInstance is already referenced, and there is no need to + reference it again. +*/ +bool QAxBase::initialize(IUnknown **ptr) +{ + if (*ptr || control().isEmpty()) + return false; + + *ptr = 0; + + bool res = false; + + const QString ctrl(d->ctrl); + if (ctrl.contains(QLatin1String("/{"))) // DCOM request + res = initializeRemote(ptr); + else if (ctrl.contains(QLatin1String("}:"))) // licensed control + res = initializeLicensed(ptr); + else if (ctrl.contains(QLatin1String("}&"))) // running object + res = initializeActive(ptr); + else if (QFile::exists(ctrl)) // existing file + res = initializeFromFile(ptr); + + if (!res) { // standard + HRESULT hres = CoCreateInstance(QUuid(ctrl), 0, CLSCTX_SERVER, IID_IUnknown, (void**)ptr); + res = S_OK == hres; +#ifndef QT_NO_DEBUG + if (!res) + qErrnoWarning(hres, "CoCreateInstance failure"); +#endif + } + + return *ptr != 0; +} + +/*! + Creates an instance of a licensed control, and returns the IUnknown interface + to the object in \a ptr. This functions returns true if successful, otherwise + returns false. + + This function is called by initialize() if the control string contains the + substring "}:". The license key needs to follow this substring. + + \sa initialize() +*/ +bool QAxBase::initializeLicensed(IUnknown** ptr) +{ + int at = control().lastIndexOf(QLatin1String("}:")); + + QString clsid(control().left(at)); + QString key(control().mid(at+2)); + + IClassFactory *factory = 0; + CoGetClassObject(QUuid(clsid), CLSCTX_SERVER, 0, IID_IClassFactory, (void**)&factory); + if (!factory) + return false; + initializeLicensedHelper(factory, key, ptr); + factory->Release(); + + return *ptr != 0; +} + +/* \internal + Called by initializeLicensed and initializedRemote to create an object + via IClassFactory2. +*/ +bool QAxBase::initializeLicensedHelper(void *f, const QString &key, IUnknown **ptr) +{ + IClassFactory *factory = (IClassFactory*)f; + IClassFactory2 *factory2 = 0; + factory->QueryInterface(IID_IClassFactory2, (void**)&factory2); + if (factory2) { + BSTR bkey = QStringToBSTR(key); + HRESULT hres = factory2->CreateInstanceLic(0, 0, IID_IUnknown, bkey, (void**)ptr); + SysFreeString(bkey); +#ifdef QT_DEBUG + LICINFO licinfo; + licinfo.cbLicInfo = sizeof(LICINFO); + factory2->GetLicInfo(&licinfo); + + if (hres != S_OK) { + SetLastError(hres); + qErrnoWarning("CreateInstanceLic failed"); + if (!licinfo.fLicVerified) { + qWarning("Wrong license key specified, and machine is not fully licensed."); + } else if (licinfo.fRuntimeKeyAvail) { + BSTR licenseKey; + factory2->RequestLicKey(0, &licenseKey); + QString qlicenseKey = QString::fromWCharArray(licenseKey); + SysFreeString(licenseKey); + qWarning("Use license key is '%s' to create object on unlicensed machine.", + qlicenseKey.toLatin1().constData()); + } + } else if (licinfo.fLicVerified) { + qWarning("Machine is fully licensed for '%s'", control().toLatin1().constData()); + if (licinfo.fRuntimeKeyAvail) { + BSTR licenseKey; + factory2->RequestLicKey(0, &licenseKey); + QString qlicenseKey = QString::fromWCharArray(licenseKey); + SysFreeString(licenseKey); + + if (qlicenseKey != key) + qWarning("Runtime license key is '%s'", qlicenseKey.toLatin1().constData()); + } + } +#else + Q_UNUSED(hres); +#endif + factory2->Release(); + } else { // give it a shot without license + factory->CreateInstance(0, IID_IUnknown, (void**)ptr); + } + return *ptr != 0; +} + + +/*! + Connects to an active instance running on the current machine, and returns the + IUnknown interface to the running object in \a ptr. This function returns true + if successful, otherwise returns false. + + This function is called by initialize() if the control string contains the + substring "}&". + + \sa initialize() +*/ +bool QAxBase::initializeActive(IUnknown** ptr) +{ +#if defined(Q_OS_WINCE) + Q_UNUSED(ptr); + return false; +#else + int at = control().lastIndexOf(QLatin1String("}&")); + QString clsid(control().left(at)); + + GetActiveObject(QUuid(clsid), 0, ptr); + + return *ptr != 0; +#endif +} + +#ifdef Q_CC_GNU +# ifndef OLEPENDER_NONE +# define OLERENDER_NONE 0 +# endif +#endif + +/*! + Creates the COM object handling the filename in the control property, and + returns the IUnknown interface to the object in \a ptr. This function returns + true if successful, otherwise returns false. + + This function is called by initialize() if the control string is the name of + an existing file. + + \sa initialize() +*/ +bool QAxBase::initializeFromFile(IUnknown** ptr) +{ +#if defined(Q_OS_WINCE) + Q_UNUSED(ptr); + return false; +#else + IStorage *storage = 0; + ILockBytes * bytes = 0; + HRESULT hres = ::CreateILockBytesOnHGlobal(0, TRUE, &bytes); + hres = ::StgCreateDocfileOnILockBytes(bytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &storage); + + hres = OleCreateFromFile(CLSID_NULL, reinterpret_cast<const wchar_t*>(control().utf16()), IID_IUnknown, OLERENDER_NONE, 0, 0, storage, (void**)ptr); + + storage->Release(); + bytes->Release(); + + return hres == S_OK; +#endif +} + + +// There seams to be a naming problem in mingw headers +#if defined(Q_CC_GNU) && !defined(COAUTHIDENTITY) && !defined(__MINGW64_VERSION_MAJOR) +#define COAUTHIDENTITY AUTH_IDENTITY +#endif + + +/*! + Creates the instance on a remote server, and returns the IUnknown interface + to the object in \a ptr. This function returns true if successful, otherwise + returns false. + + This function is called by initialize() if the control string contains the + substring "/{". The information about the remote machine needs to be provided + in front of the substring. + + \sa initialize() +*/ +bool QAxBase::initializeRemote(IUnknown** ptr) +{ + int at = control().lastIndexOf(QLatin1String("/{")); + + QString server(control().left(at)); + QString clsid(control().mid(at+1)); + + QString user; + QString domain; + QString passwd; + QString key; + + at = server.indexOf(QChar::fromLatin1('@')); + if (at != -1) { + user = server.left(at); + server = server.mid(at+1); + + at = user.indexOf(QChar::fromLatin1(':')); + if (at != -1) { + passwd = user.mid(at+1); + user = user.left(at); + } + at = user.indexOf(QChar::fromLatin1('/')); + if (at != -1) { + domain = user.left(at); + user = user.mid(at+1); + } + } + + at = clsid.lastIndexOf(QLatin1String("}:")); + if (at != -1) { + key = clsid.mid(at+2); + clsid = clsid.left(at); + } + + d->ctrl = server + QChar::fromLatin1('/') + clsid; + if (!key.isEmpty()) + d->ctrl = d->ctrl + QChar::fromLatin1(':') + key; + + COAUTHIDENTITY authIdentity; + authIdentity.UserLength = user.length(); + authIdentity.User = authIdentity.UserLength ? (ushort*)user.utf16() : 0; + authIdentity.DomainLength = domain.length(); + authIdentity.Domain = authIdentity.DomainLength ? (ushort*)domain.utf16() : 0; + authIdentity.PasswordLength = passwd.length(); + authIdentity.Password = authIdentity.PasswordLength ? (ushort*)passwd.utf16() : 0; + authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + + COAUTHINFO authInfo; + authInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT; + authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE; + authInfo.pwszServerPrincName = 0; + authInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT; + authInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE; + authInfo.pAuthIdentityData = &authIdentity; + authInfo.dwCapabilities = 0; + + COSERVERINFO serverInfo; + serverInfo.dwReserved1 = 0; + serverInfo.dwReserved2 = 0; + serverInfo.pAuthInfo = &authInfo; + serverInfo.pwszName = (wchar_t*)server.utf16(); + + IClassFactory *factory = 0; + HRESULT res = CoGetClassObject(QUuid(clsid), CLSCTX_REMOTE_SERVER, &serverInfo, IID_IClassFactory, (void**)&factory); + if (factory) { + if (!key.isEmpty()) + initializeLicensedHelper(factory, key, ptr); + else + res = factory->CreateInstance(0, IID_IUnknown, (void**)ptr); + factory->Release(); + } +#ifndef QT_NO_DEBUG + if (res != S_OK) + qErrnoWarning(res, "initializeRemote Failed"); +#endif + + return res == S_OK; +} + +/*! + Requests the interface \a uuid from the COM object and sets the + value of \a iface to the provided interface, or to 0 if the + requested interface could not be provided. + + Returns the result of the QueryInterface implementation of the COM object. + + \sa control +*/ +long QAxBase::queryInterface(const QUuid &uuid, void **iface) const +{ + *iface = 0; + if (!d->ptr) { + ((QAxBase*)this)->initialize(&d->ptr); + d->initialized = true; + } + + if (d->ptr && !uuid.isNull()) + return d->ptr->QueryInterface(uuid, iface); + + return E_NOTIMPL; +} + +class MetaObjectGenerator +{ +public: + MetaObjectGenerator(QAxBase *ax, QAxBasePrivate *dptr); + MetaObjectGenerator(ITypeLib *typelib, ITypeInfo *typeinfo); + ~MetaObjectGenerator(); + + QMetaObject *metaObject(const QMetaObject *parentObject, const QByteArray &className = QByteArray()); + + void readClassInfo(); + void readEnumInfo(); + void readInterfaceInfo(); + void readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs); + void readVarsInfo(ITypeInfo *typeinfo, ushort nVars); + void readEventInfo(); + void readEventInterface(ITypeInfo *eventinfo, IConnectionPoint *cpoint); + + inline void addClassInfo(const char *key, const char *value) + { + classinfo_list.insert(key, value); + } + +private: + void init(); + + + QMetaObject *tryCache(); + + QByteArray createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names, + QByteArray &type, QList<QByteArray> ¶meters); + + QByteArray usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function); + QByteArray guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function); + + // ### from qmetaobject.cpp + enum ProperyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + // And our own - don't use the upper byte, as it's used for the property type + RequestingEdit = 0x00400000, + Bindable = 0x00800000 + }; + enum MemberFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + MemberMethod = 0x00, + MemberSignal = 0x04, + MemberSlot = 0x08, + MemberCompatibility = 0x10, + MemberCloned = 0x20, + MemberScriptable = 0x40, + }; + + inline QList<QByteArray> paramList(const QByteArray &proto) + { + QByteArray prototype(proto); + QByteArray parameters = prototype.mid(prototype.indexOf('(') + 1); + parameters.truncate(parameters.length() - 1); + + QList<QByteArray> plist = parameters.split(','); + return plist; + } + + inline QByteArray replaceType(const QByteArray &type) + { + int i = 0; + while (type_conversion[i][0]) { + int len = int(strlen(type_conversion[i][0])); + int ti; + if ((ti = type.indexOf(type_conversion[i][0])) != -1) { + QByteArray rtype(type); + rtype.replace(ti, len, type_conversion[i][1]); + return rtype; + } + ++i; + } + return type; + } + + QByteArray replacePrototype(const QByteArray &prototype) + { + QByteArray proto(prototype); + + QList<QByteArray> plist = paramList(prototype); + for (int p = 0; p < plist.count(); ++p) { + QByteArray param(plist.at(p)); + if (param != replaceType(param)) { + int type = 0; + while (type_conversion[type][0]) { + int paren = proto.indexOf('('); + while ((paren = proto.indexOf(type_conversion[type][0])) != -1) { + proto.replace(paren, qstrlen(type_conversion[type][0]), type_conversion[type][1]); + } + ++type; + } + break; + } + } + + return proto; + } + + QMap<QByteArray, QByteArray> classinfo_list; + + inline bool hasClassInfo(const char *key) + { + return classinfo_list.contains(key); + } + + struct Method { + Method() : flags(0) + {} + QByteArray type; + QByteArray parameters; + int flags; + QByteArray realPrototype; + }; + QMap<QByteArray, Method> signal_list; + inline void addSignal(const QByteArray &prototype, const QByteArray ¶meters) + { + QByteArray proto(replacePrototype(prototype)); + + Method &signal = signal_list[proto]; + signal.type = 0; + signal.parameters = parameters; + signal.flags = QMetaMethod::Public | MemberSignal; + if (proto != prototype) + signal.realPrototype = prototype; + } + + void addChangedSignal(const QByteArray &function, const QByteArray &type, int memid); + + inline bool hasSignal(const QByteArray &prototype) + { + return signal_list.contains(prototype); + } + + QMap<QByteArray, Method> slot_list; + inline void addSlot(const QByteArray &type, const QByteArray &prototype, const QByteArray ¶meters, int flags = QMetaMethod::Public) + { + QByteArray proto = replacePrototype(prototype); + + Method &slot = slot_list[proto]; + slot.type = replaceType(type); + slot.parameters = parameters; + slot.flags = flags | MemberSlot; + if (proto != prototype) + slot.realPrototype = prototype; + } + + void addSetterSlot(const QByteArray &property); + + inline bool hasSlot(const QByteArray &prototype) + { + return slot_list.contains(prototype); + } + + struct Property { + Property() : typeId(0) + {} + QByteArray type; + uint typeId; + QByteArray realType; + }; + QMap<QByteArray, Property> property_list; + void addProperty(const QByteArray &type, const QByteArray &name, uint flags) + { + QByteArray propertyType(type); + if (propertyType.endsWith('&')) + propertyType.chop(1); + + Property &prop = property_list[name]; + if (!propertyType.isEmpty() && propertyType != "HRESULT") { + prop.type = replaceType(propertyType); + if (prop.type != propertyType) + prop.realType = propertyType; + } + if (flags & Writable) + flags |= Stored; + prop.typeId |= flags; + QVariant::Type vartype = QVariant::nameToType(prop.type); + switch(vartype) { + case QVariant::Invalid: + case QVariant::UserType: + if (prop.type == "QVariant") { + prop.typeId |= 0xff << 24; + break; + } + if (QMetaType::type(prop.type) == -1) + qWarning("QAxBase: Unsupported property type: %s", prop.type.data()); + break; + default: + prop.typeId |= vartype << 24; + break; + } + } + + inline bool hasProperty(const QByteArray &name) + { + return property_list.contains(name); + } + + inline QByteArray propertyType(const QByteArray &name) + { + return property_list.value(name).type; + } + + QMap<QByteArray, QList<QPair<QByteArray, int> > > enum_list; + inline void addEnumValue(const QByteArray &enumname, const QByteArray &key, int value) + { + enum_list[enumname].append(QPair<QByteArray, int>(key, value)); + } + + inline bool hasEnum(const QByteArray &enumname) + { + return enum_list.contains(enumname); + } + + QAxBase *that; + QAxBasePrivate *d; + + IDispatch *disp; + ITypeInfo *dispInfo; + ITypeInfo *classInfo; + ITypeLib *typelib; + QByteArray current_typelib; + + QSettings iidnames; + QString cacheKey; + QByteArray debugInfo; + + QUuid iid_propNotifySink; + + friend QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject); +}; + +QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject) +{ + MetaObjectGenerator generator(typeLib, 0); + + generator.readEnumInfo(); + return generator.metaObject(parentObject, "EnumInfo"); +} + +QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject) +{ + MetaObjectGenerator generator(typeLib, typeInfo); + + QString className; + BSTR bstr; + if (S_OK != typeInfo->GetDocumentation(-1, &bstr, 0, 0, 0)) + return 0; + + className = QString::fromWCharArray(bstr); + SysFreeString(bstr); + + generator.readEnumInfo(); + generator.readFuncsInfo(typeInfo, 0); + generator.readVarsInfo(typeInfo, 0); + + return generator.metaObject(parentObject, className.toLatin1()); +} + +QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject) +{ + MetaObjectGenerator generator(typeLib, 0); + generator.addSignal("exception(int,QString,QString,QString)", "code,source,disc,help"); + generator.addSignal("propertyChanged(QString)", "name"); + + QString className; + BSTR bstr; + if (S_OK != classInfo->GetDocumentation(-1, &bstr, 0, 0, 0)) + return 0; + + className = QString::fromWCharArray(bstr); + SysFreeString(bstr); + + generator.readEnumInfo(); + + TYPEATTR *typeattr; + classInfo->GetTypeAttr(&typeattr); + if (typeattr) { + int nInterfaces = typeattr->cImplTypes; + classInfo->ReleaseTypeAttr(typeattr); + + for (int index = 0; index < nInterfaces; ++index) { + HREFTYPE refType; + if (S_OK != classInfo->GetRefTypeOfImplType(index, &refType)) + continue; + + int flags = 0; + classInfo->GetImplTypeFlags(index, &flags); + if (flags & IMPLTYPEFLAG_FRESTRICTED) + continue; + + ITypeInfo *interfaceInfo = 0; + classInfo->GetRefTypeInfo(refType, &interfaceInfo); + if (!interfaceInfo) + continue; + + interfaceInfo->GetDocumentation(-1, &bstr, 0, 0, 0); + QString interfaceName = QString::fromWCharArray(bstr); + SysFreeString(bstr); + QByteArray key; + + TYPEATTR *typeattr = 0; + interfaceInfo->GetTypeAttr(&typeattr); + + if (flags & IMPLTYPEFLAG_FSOURCE) { + if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN)) + key = "Event Interface " + QByteArray::number(index); + generator.readEventInterface(interfaceInfo, 0); + } else { + if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN)) + key = "Interface " + QByteArray::number(index); + generator.readFuncsInfo(interfaceInfo, 0); + generator.readVarsInfo(interfaceInfo, 0); + } + if (!key.isEmpty()) + generator.addClassInfo(key.data(), interfaceName.toLatin1()); + + if (typeattr) + interfaceInfo->ReleaseTypeAttr(typeattr); + interfaceInfo->Release(); + } + } + + return generator.metaObject(parentObject, className.toLatin1()); +} + +MetaObjectGenerator::MetaObjectGenerator(QAxBase *ax, QAxBasePrivate *dptr) +: that(ax), d(dptr), disp(0), dispInfo(0), classInfo(0), typelib(0), + iidnames(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat) +{ + init(); +} + +MetaObjectGenerator::MetaObjectGenerator(ITypeLib *tlib, ITypeInfo *tinfo) +: that(0), d(0), disp(0), dispInfo(tinfo), classInfo(0), typelib(tlib), + iidnames(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat) +{ + init(); + + if (dispInfo) + dispInfo->AddRef(); + if (typelib) { + typelib->AddRef(); + BSTR bstr; + typelib->GetDocumentation(-1, &bstr, 0, 0, 0); + current_typelib = QString::fromWCharArray(bstr).toLatin1(); + SysFreeString(bstr); + } + readClassInfo(); +} + +void MetaObjectGenerator::init() +{ + if (d) + disp = d->dispatch(); + + iid_propNotifySink = IID_IPropertyNotifySink; + + addSignal("signal(QString,int,void*)", "name,argc,argv"); + addSignal("exception(int,QString,QString,QString)", "code,source,disc,help"); + addSignal("propertyChanged(QString)", "name"); + if (d || dispInfo) { + addProperty("QString", "control", Readable|Writable|Designable|Scriptable|Stored|Editable|StdCppSet); + } +} + +MetaObjectGenerator::~MetaObjectGenerator() +{ + if (dispInfo) dispInfo->Release(); + if (classInfo) classInfo->Release(); + if (typelib) typelib->Release(); +} + +bool qax_dispatchEqualsIDispatch = true; +QList<QByteArray> qax_qualified_usertypes; + +QByteArray MetaObjectGenerator::usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function) +{ + HREFTYPE usertype = tdesc.hreftype; + if (tdesc.vt != VT_USERDEFINED) + return 0; + + QByteArray typeName; + ITypeInfo *usertypeinfo = 0; + info->GetRefTypeInfo(usertype, &usertypeinfo); + if (usertypeinfo) { + ITypeLib *usertypelib = 0; + UINT index; + usertypeinfo->GetContainingTypeLib(&usertypelib, &index); + if (usertypelib) { + // get type library name + BSTR typelibname = 0; + usertypelib->GetDocumentation(-1, &typelibname, 0, 0, 0); + QByteArray typeLibName = QString::fromWCharArray(typelibname).toLatin1(); + SysFreeString(typelibname); + + // get type name + BSTR usertypename = 0; + usertypelib->GetDocumentation(index, &usertypename, 0, 0, 0); + QByteArray userTypeName = QString::fromWCharArray(usertypename).toLatin1(); + SysFreeString(usertypename); + + if (hasEnum(userTypeName)) // known enum? + typeName = userTypeName; + else if (userTypeName == "OLE_COLOR" || userTypeName == "VB_OLE_COLOR") + typeName = "QColor"; + else if (userTypeName == "IFontDisp" || userTypeName == "IFontDisp*" || userTypeName == "IFont" || userTypeName == "IFont*") + typeName = "QFont"; + else if (userTypeName == "Picture" || userTypeName == "Picture*") + typeName = "QPixmap"; + + if (typeName.isEmpty()) { + TYPEATTR *typeattr = 0; + usertypeinfo->GetTypeAttr(&typeattr); + if (typeattr) { + switch(typeattr->typekind) { + case TKIND_ALIAS: + userTypeName = guessTypes(typeattr->tdescAlias, usertypeinfo, function); + break; + case TKIND_DISPATCH: + case TKIND_COCLASS: + if (qax_dispatchEqualsIDispatch) { + userTypeName = "IDispatch"; + } else { + if (typeLibName != current_typelib) + userTypeName = typeLibName + "::" + userTypeName; + if (!qax_qualified_usertypes.contains(userTypeName)) + qax_qualified_usertypes << userTypeName; + } + break; + case TKIND_ENUM: + if (typeLibName != current_typelib) + userTypeName = typeLibName + "::" + userTypeName; + if (!qax_qualified_usertypes.contains("enum " + userTypeName)) + qax_qualified_usertypes << "enum " + userTypeName; + break; + case TKIND_INTERFACE: + if (typeLibName != current_typelib) + userTypeName = typeLibName + "::" + userTypeName; + if (!qax_qualified_usertypes.contains(userTypeName)) + qax_qualified_usertypes << userTypeName; + break; + case TKIND_RECORD: + if (!qax_qualified_usertypes.contains("struct " + userTypeName)) + qax_qualified_usertypes << "struct "+ userTypeName; + break; + default: + break; + } + } + + usertypeinfo->ReleaseTypeAttr(typeattr); + typeName = userTypeName; + } + usertypelib->Release(); + } + usertypeinfo->Release(); + } + + return typeName; +} + +#define VT_UNHANDLED(x) case VT_##x: qWarning("QAxBase: Unhandled type %s", #x); str = #x; break; + +QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function) +{ + QByteArray str; + switch (tdesc.vt) { + case VT_EMPTY: + case VT_VOID: + break; + case VT_LPWSTR: + str = "wchar_t *"; + break; + case VT_BSTR: + str = "QString"; + break; + case VT_BOOL: + str = "bool"; + break; + case VT_I1: + str = "char"; + break; + case VT_I2: + str = "short"; + break; + case VT_I4: + case VT_INT: + str = "int"; + break; + case VT_I8: + str = "qlonglong"; + break; + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_UINT: + str = "uint"; + break; + case VT_UI8: + str = "qulonglong"; + break; + case VT_CY: + str = "qlonglong"; + break; + case VT_R4: + str = "float"; + break; + case VT_R8: + str = "double"; + break; + case VT_DATE: + str = "QDateTime"; + break; + case VT_DISPATCH: + str = "IDispatch*"; + break; + case VT_VARIANT: + str = "QVariant"; + break; + case VT_UNKNOWN: + str = "IUnknown*"; + break; + case VT_HRESULT: + str = "HRESULT"; + break; + case VT_PTR: + str = guessTypes(*tdesc.lptdesc, info, function); + switch(tdesc.lptdesc->vt) { + case VT_VOID: + str = "void*"; + break; + case VT_VARIANT: + case VT_BSTR: + case VT_I1: + case VT_I2: + case VT_I4: + case VT_I8: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_UI8: + case VT_BOOL: + case VT_R4: + case VT_R8: + case VT_INT: + case VT_UINT: + case VT_CY: + str += '&'; + break; + case VT_PTR: + if (str == "QFont" || str == "QPixmap") { + str += '&'; + break; + } else if (str == "void*") { + str = "void **"; + break; + } + // FALLTHROUGH + default: + if (str == "QColor") + str += '&'; + else if (str == "QDateTime") + str += '&'; + else if (str == "QVariantList") + str += '&'; + else if (str == "QByteArray") + str += '&'; + else if (str == "QStringList") + str += '&'; + else if (!str.isEmpty() && hasEnum(str)) + str += '&'; + else if (!str.isEmpty() && str != "QFont" && str != "QPixmap" && str != "QVariant") + str += '*'; + } + break; + case VT_SAFEARRAY: + switch(tdesc.lpadesc->tdescElem.vt) { + // some shortcuts, and generic support for lists of QVariant-supported types + case VT_UI1: + str = "QByteArray"; + break; + case VT_BSTR: + str = "QStringList"; + break; + case VT_VARIANT: + str = "QVariantList"; + break; + default: + str = guessTypes(tdesc.lpadesc->tdescElem, info, function); + if (!str.isEmpty()) + str = "QList<" + str + '>'; + break; + } + break; + case VT_CARRAY: + str = guessTypes(tdesc.lpadesc->tdescElem, info, function); + if (!str.isEmpty()) { + for (int index = 0; index < tdesc.lpadesc->cDims; ++index) + str += '[' + QByteArray::number((int)tdesc.lpadesc->rgbounds[index].cElements) + ']'; + } + break; + case VT_USERDEFINED: + str = usertypeToString(tdesc, info, function); + break; + + VT_UNHANDLED(FILETIME); + VT_UNHANDLED(BLOB); + VT_UNHANDLED(ERROR); + VT_UNHANDLED(DECIMAL); + VT_UNHANDLED(LPSTR); + default: + break; + } + + if (tdesc.vt & VT_BYREF) + str += '&'; + + str.replace("&*", "**"); + return str; +} + +void MetaObjectGenerator::readClassInfo() +{ + // Read class information + IProvideClassInfo *provideClassInfo = 0; + if (d) + d->ptr->QueryInterface(IID_IProvideClassInfo, (void**)&provideClassInfo); + if (provideClassInfo) { + provideClassInfo->GetClassInfo(&classInfo); + TYPEATTR *typeattr = 0; + if (classInfo) + classInfo->GetTypeAttr(&typeattr); + + QString coClassID; + if (typeattr) { + QUuid clsid(typeattr->guid); + coClassID = clsid.toString().toUpper(); +#ifndef QAX_NO_CLASSINFO + // UUID + if (d->useClassInfo && !hasClassInfo("CoClass")) { + QString coClassIDstr = iidnames.value(QLatin1String("/CLSID/") + coClassID + QLatin1String("/Default"), coClassID).toString(); + addClassInfo("CoClass", coClassIDstr.isEmpty() ? coClassID.toLatin1() : coClassIDstr.toLatin1()); + QByteArray version = QByteArray::number(typeattr->wMajorVerNum) + '.' + QByteArray::number(typeattr->wMinorVerNum); + if (version != "0.0") + addClassInfo("Version", version); + } +#endif + classInfo->ReleaseTypeAttr(typeattr); + } + provideClassInfo->Release(); + provideClassInfo = 0; + + if (d->tryCache && !coClassID.isEmpty()) + cacheKey = QString::fromLatin1("%1$%2$%3$%4").arg(coClassID) + .arg((int)d->useEventSink).arg((int)d->useClassInfo).arg((int)qax_dispatchEqualsIDispatch); + } + + UINT index = 0; + if (disp && !dispInfo) + disp->GetTypeInfo(index, LOCALE_USER_DEFAULT, &dispInfo); + + if (dispInfo && !typelib) + dispInfo->GetContainingTypeLib(&typelib, &index); + + if (!typelib) { + QSettings controls(QLatin1String("HKEY_LOCAL_MACHINE\\Software"), QSettings::NativeFormat); + QString tlid = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/TypeLib/.")).toString(); + QString tlfile; + if (!tlid.isEmpty()) { + controls.beginGroup(QLatin1String("/Classes/TypeLib/") + tlid); + QStringList versions = controls.childGroups(); + QStringList::Iterator vit = versions.begin(); + while (tlfile.isEmpty() && vit != versions.end()) { + QString version = *vit; + ++vit; + tlfile = controls.value(QLatin1Char('/') + version + QLatin1String("/0/win32/.")).toString(); + } + controls.endGroup(); + } else { + tlfile = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/InprocServer32/.")).toString(); + if (tlfile.isEmpty()) + tlfile = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/LocalServer32/.")).toString(); + } + if (!tlfile.isEmpty()) { + LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib); + if (!typelib) { + tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".tlb"); + LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib); + } + if (!typelib) { + tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".olb"); + LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib); + } + } + } + + if (!classInfo && typelib && that) + typelib->GetTypeInfoOfGuid(QUuid(that->control()), &classInfo); + + if (classInfo && !dispInfo) { + TYPEATTR *classAttr; + classInfo->GetTypeAttr(&classAttr); + if (classAttr) { + for (int i = 0; i < classAttr->cImplTypes; ++i) { + int typeFlags = 0; + classInfo->GetImplTypeFlags(i, &typeFlags); + if (typeFlags & IMPLTYPEFLAG_FSOURCE) + continue; + + HREFTYPE hrefType; + if (S_OK == classInfo->GetRefTypeOfImplType(i, &hrefType)) + classInfo->GetRefTypeInfo(hrefType, &dispInfo); + if (dispInfo) { + TYPEATTR *ifaceAttr; + dispInfo->GetTypeAttr(&ifaceAttr); + WORD typekind = ifaceAttr->typekind; + dispInfo->ReleaseTypeAttr(ifaceAttr); + + if (typekind & TKIND_DISPATCH) { + break; + } else { + dispInfo->Release(); + dispInfo = 0; + } + } + } + classInfo->ReleaseTypeAttr(classAttr); + } + } + + if (!d || !dispInfo || !cacheKey.isEmpty() || !d->tryCache) + return; + + TYPEATTR *typeattr = 0; + dispInfo->GetTypeAttr(&typeattr); + + QString interfaceID; + if (typeattr) { + QUuid iid(typeattr->guid); + interfaceID = iid.toString().toUpper(); + + dispInfo->ReleaseTypeAttr(typeattr); + // ### event interfaces!! + if (!interfaceID.isEmpty()) + cacheKey = QString::fromLatin1("%1$%2$%3$%4").arg(interfaceID) + .arg((int)d->useEventSink).arg((int)d->useClassInfo).arg((int)qax_dispatchEqualsIDispatch); + } +} + +void MetaObjectGenerator::readEnumInfo() +{ + if (!typelib) + return; + + QUuid libUuid; + + if (d && d->tryCache) { + TLIBATTR *libAttr = 0; + typelib->GetLibAttr(&libAttr); + if (libAttr) { + libUuid = QUuid(libAttr->guid); + typelib->ReleaseTLibAttr(libAttr); + enum_list = enum_cache.value(libUuid); + if (!enum_list.isEmpty()) + return; + } + } + + int valueindex = 0; + QSet<QString> clashCheck; + int clashIndex = 0; + + int enum_serial = 0; + UINT index = typelib->GetTypeInfoCount(); + for (UINT i = 0; i < index; ++i) { + TYPEKIND typekind; + typelib->GetTypeInfoType(i, &typekind); + if (typekind == TKIND_ENUM) { + // Get the type information for the enum + ITypeInfo *enuminfo = 0; + typelib->GetTypeInfo(i, &enuminfo); + if (!enuminfo) + continue; + + // Get the name of the enumeration + BSTR enumname; + QByteArray enumName; + if (typelib->GetDocumentation(i, &enumname, 0, 0, 0) == S_OK) { + enumName = QString::fromWCharArray(enumname).toLatin1(); + SysFreeString(enumname); + } else { + enumName = "enum" + QByteArray::number(++enum_serial); + } + + // Get the attributes of the enum type + TYPEATTR *typeattr = 0; + enuminfo->GetTypeAttr(&typeattr); + if (typeattr) { + // Get all values of the enumeration + for (UINT vd = 0; vd < (UINT)typeattr->cVars; ++vd) { + VARDESC *vardesc = 0; + enuminfo->GetVarDesc(vd, &vardesc); + if (vardesc && vardesc->varkind == VAR_CONST) { + int value = vardesc->lpvarValue->lVal; + int memid = vardesc->memid; + // Get the name of the value + BSTR valuename; + QByteArray valueName; + UINT maxNamesOut; + enuminfo->GetNames(memid, &valuename, 1, &maxNamesOut); + if (maxNamesOut) { + valueName = QString::fromWCharArray(valuename).toLatin1(); + SysFreeString(valuename); + } else { + valueName = "value" + QByteArray::number(valueindex++); + } + + if (clashCheck.contains(QString::fromLatin1(valueName))) + valueName += QByteArray::number(++clashIndex); + + clashCheck.insert(QString::fromLatin1(valueName)); + addEnumValue(enumName, valueName, value); + } + enuminfo->ReleaseVarDesc(vardesc); + } + } + enuminfo->ReleaseTypeAttr(typeattr); + enuminfo->Release(); + } + } + + if (!libUuid.isNull()) + enum_cache.insert(libUuid, enum_list); +} + +void MetaObjectGenerator::addChangedSignal(const QByteArray &function, const QByteArray &type, int memid) +{ + QAxEventSink *eventSink = 0; + if (d) { + eventSink = d->eventSink.value(iid_propNotifySink); + if (!eventSink && d->useEventSink) { + eventSink = new QAxEventSink(that); + d->eventSink.insert(iid_propNotifySink, eventSink); + } + } + // generate changed signal + QByteArray signalName(function); + signalName += "Changed"; + QByteArray signalProto = signalName + '(' + replaceType(type) + ')'; + if (!hasSignal(signalProto)) + addSignal(signalProto, function); + if (eventSink) + eventSink->addProperty(memid, function, signalProto); +} + +void MetaObjectGenerator::addSetterSlot(const QByteArray &property) +{ + QByteArray set; + QByteArray prototype(property); + if (isupper(prototype.at(0))) { + set = "Set"; + } else { + set = "set"; + prototype[0] = toupper(prototype[0]); + } + prototype = set + prototype + '(' + propertyType(property) + ')'; + if (!hasSlot(prototype)) + addSlot(0, prototype, property); +} + +QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names, + QByteArray &type, QList<QByteArray> ¶meters) +{ + QByteArray prototype; + QByteArray function(names.at(0)); + const QByteArray hresult("HRESULT"); + // get function prototype + type = guessTypes(funcdesc->elemdescFunc.tdesc, typeinfo, function); + if ((type.isEmpty() || type == hresult) && funcdesc->invkind == INVOKE_PROPERTYPUT && funcdesc->lprgelemdescParam) { + type = guessTypes(funcdesc->lprgelemdescParam->tdesc, typeinfo, function); + } + + prototype = function + '('; + if (funcdesc->invkind == INVOKE_FUNC && type == hresult) + type = 0; + + int p; + for (p = 1; p < names.count(); ++p) { + // parameter + QByteArray paramName = names.at(p); + bool optional = p > (funcdesc->cParams - funcdesc->cParamsOpt); + TYPEDESC tdesc = funcdesc->lprgelemdescParam[p-1].tdesc; + PARAMDESC pdesc = funcdesc->lprgelemdescParam[p-1].paramdesc; + + QByteArray ptype = guessTypes(tdesc, typeinfo, function); + if (pdesc.wParamFlags & PARAMFLAG_FRETVAL) { + if (ptype.endsWith('&')) { + ptype.truncate(ptype.length() - 1); + } else if (ptype.endsWith("**")) { + ptype.truncate(ptype.length() - 1); + } + type = ptype; + } else { + prototype += ptype; + if (pdesc.wParamFlags & PARAMFLAG_FOUT && !ptype.endsWith('&') && !ptype.endsWith("**")) + prototype += '&'; + if (optional || pdesc.wParamFlags & PARAMFLAG_FOPT) + paramName += "=0"; + else if (pdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) { + // ### get the value from pdesc.pparamdescex + paramName += "=0"; + } + parameters << paramName; + } + if (p < funcdesc->cParams && !(pdesc.wParamFlags & PARAMFLAG_FRETVAL)) + prototype += ','; + } + + if (!prototype.isEmpty()) { + if (prototype.endsWith(',')) { + if (funcdesc->invkind == INVOKE_PROPERTYPUT && p == funcdesc->cParams) { + TYPEDESC tdesc = funcdesc->lprgelemdescParam[p-1].tdesc; + QByteArray ptype = guessTypes(tdesc, typeinfo, function); + prototype += ptype; + prototype += ')'; + parameters << "rhs"; + } else { + prototype[prototype.length()-1] = ')'; + } + } else { + prototype += ')'; + } + } + + return prototype; +} + +void MetaObjectGenerator::readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs) +{ + if (!nFuncs) { + TYPEATTR *typeattr = 0; + typeinfo->GetTypeAttr(&typeattr); + if (typeattr) { + nFuncs = typeattr->cFuncs; + typeinfo->ReleaseTypeAttr(typeattr); + } + } + + // get information about all functions + for (ushort fd = 0; fd < nFuncs ; ++fd) { + FUNCDESC *funcdesc = 0; + typeinfo->GetFuncDesc(fd, &funcdesc); + if (!funcdesc) + break; + + QByteArray function; + QByteArray type; + QByteArray prototype; + QList<QByteArray> parameters; + + // parse function description + BSTR bstrNames[256]; + UINT maxNames = 255; + UINT maxNamesOut; + typeinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut); + QList<QByteArray> names; + int p; + for (p = 0; p < (int)maxNamesOut; ++p) { + names << QString::fromWCharArray(bstrNames[p]).toLatin1(); + SysFreeString(bstrNames[p]); + } + + // function name + function = names.at(0); + if ((maxNamesOut == 3 && function == "QueryInterface") || + (maxNamesOut == 1 && function == "AddRef") || + (maxNamesOut == 1 && function == "Release") || + (maxNamesOut == 9 && function == "Invoke") || + (maxNamesOut == 6 && function == "GetIDsOfNames") || + (maxNamesOut == 2 && function == "GetTypeInfoCount") || + (maxNamesOut == 4 && function == "GetTypeInfo")) { + typeinfo->ReleaseFuncDesc(funcdesc); + continue; + } + + prototype = createPrototype(/*in*/ funcdesc, typeinfo, names, /*out*/type, parameters); + + // get type of function + switch(funcdesc->invkind) { + case INVOKE_PROPERTYGET: // property + case INVOKE_PROPERTYPUT: + if (funcdesc->cParams - funcdesc->cParamsOpt <= 1) { + bool dontBreak = false; + // getter with non-default-parameters -> fall through to function handling + if (funcdesc->invkind == INVOKE_PROPERTYGET && parameters.count() && funcdesc->cParams - funcdesc->cParamsOpt) { + dontBreak = true; + } else { + uint flags = Readable; + if (funcdesc->invkind != INVOKE_PROPERTYGET) + flags |= Writable; + if (!(funcdesc->wFuncFlags & (FUNCFLAG_FNONBROWSABLE | FUNCFLAG_FHIDDEN))) + flags |= Designable; + if (!(funcdesc->wFuncFlags & FUNCFLAG_FRESTRICTED)) + flags |= Scriptable; + if (funcdesc->wFuncFlags & FUNCFLAG_FREQUESTEDIT) + flags |= RequestingEdit; + if (hasEnum(type)) + flags |= EnumOrFlag; + + if (funcdesc->wFuncFlags & FUNCFLAG_FBINDABLE && funcdesc->invkind == INVOKE_PROPERTYGET) { + addChangedSignal(function, type, funcdesc->memid); + flags |= Bindable; + } + // Don't generate code for properties without type + if (type.isEmpty()) + break; + addProperty(type, function, flags); + + // more parameters -> function handling + if (funcdesc->invkind == INVOKE_PROPERTYGET && funcdesc->cParams) + dontBreak = true; + } + + if (!funcdesc->cParams) { + // don't generate slots for incomplete properties + if (type.isEmpty()) + break; + + // Done for getters + if (funcdesc->invkind == INVOKE_PROPERTYGET) + break; + + // generate setter slot + if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) { + addSetterSlot(function); + break; + } + } else if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) { + addSetterSlot(function); + // more parameters -> function handling + if (funcdesc->cParams > 1) + dontBreak = true; + } + if (!dontBreak) + break; + } + if (funcdesc->invkind == INVOKE_PROPERTYPUT) { + // remove the typename guessed for property setters + // its done only for setter's with more than one parameter. + if (funcdesc->cParams - funcdesc->cParamsOpt > 1) { + type.clear(); + } + QByteArray set; + if (isupper(prototype.at(0))) { + set = "Set"; + } else { + set = "set"; + prototype[0] = toupper(prototype[0]); + } + + prototype = set + prototype; + } + // FALL THROUGH to support multi-variat properties + case INVOKE_FUNC: // method + { + bool cloned = false; + bool defargs; + do { + QByteArray pnames; + for (p = 0; p < parameters.count(); ++p) { + pnames += parameters.at(p); + if (p < parameters.count() - 1) + pnames += ','; + } + defargs = pnames.contains("=0"); + int flags = QMetaMethod::Public; + if (cloned) + flags |= QMetaMethod::Cloned << 4; + cloned |= defargs; + addSlot(type, prototype, pnames.replace("=0", ""), flags); + + if (defargs) { + parameters.takeLast(); + int lastParam = prototype.lastIndexOf(','); + if (lastParam == -1) + lastParam = prototype.indexOf('(') + 1; + prototype.truncate(lastParam); + prototype += ')'; + } + } while (defargs); + } + break; + + default: + break; + } +#if 0 // documentation in metaobject would be cool? + // get function documentation + BSTR bstrDocu; + info->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0); + QString strDocu = QString::fromWCharArray(bstrDocu); + SysFreeString(bstrDocu); + if (!!strDocu) + desc += '[' + strDocu + ']'; + desc += '\n'; +#endif + typeinfo->ReleaseFuncDesc(funcdesc); + } +} + +void MetaObjectGenerator::readVarsInfo(ITypeInfo *typeinfo, ushort nVars) +{ + if (!nVars) { + TYPEATTR *typeattr = 0; + typeinfo->GetTypeAttr(&typeattr); + if (typeattr) { + nVars = typeattr->cVars; + typeinfo->ReleaseTypeAttr(typeattr); + } + } + + // get information about all variables + for (ushort vd = 0; vd < nVars; ++vd) { + VARDESC *vardesc; + typeinfo->GetVarDesc(vd, &vardesc); + if (!vardesc) + break; + + // no use if it's not a dispatched variable + if (vardesc->varkind != VAR_DISPATCH) { + typeinfo->ReleaseVarDesc(vardesc); + continue; + } + + // get variable name + BSTR bstrName; + UINT maxNames = 1; + UINT maxNamesOut; + typeinfo->GetNames(vardesc->memid, &bstrName, maxNames, &maxNamesOut); + if (maxNamesOut != 1 || !bstrName) { + typeinfo->ReleaseVarDesc(vardesc); + continue; + } + QByteArray variableType; + QByteArray variableName; + uint flags = 0; + + variableName = QString::fromWCharArray(bstrName).toLatin1(); + SysFreeString(bstrName); + + // get variable type + TYPEDESC typedesc = vardesc->elemdescVar.tdesc; + variableType = guessTypes(typedesc, typeinfo, variableName); + + // generate meta property + if (!hasProperty(variableName)) { + flags = Readable; + if (!(vardesc->wVarFlags & VARFLAG_FREADONLY)) + flags |= Writable; + if (!(vardesc->wVarFlags & (VARFLAG_FNONBROWSABLE | VARFLAG_FHIDDEN))) + flags |= Designable; + if (!(vardesc->wVarFlags & VARFLAG_FRESTRICTED)) + flags |= Scriptable; + if (vardesc->wVarFlags & VARFLAG_FREQUESTEDIT) + flags |= RequestingEdit; + if (hasEnum(variableType)) + flags |= EnumOrFlag; + + if (vardesc->wVarFlags & VARFLAG_FBINDABLE) { + addChangedSignal(variableName, variableType, vardesc->memid); + flags |= Bindable; + } + addProperty(variableType, variableName, flags); + } + + // generate a set slot + if (!(vardesc->wVarFlags & VARFLAG_FREADONLY)) + addSetterSlot(variableName); + +#if 0 // documentation in metaobject would be cool? + // get function documentation + BSTR bstrDocu; + info->GetDocumentation(vardesc->memid, 0, &bstrDocu, 0, 0); + QString strDocu = QString::fromWCharArray(bstrDocu); + SysFreeString(bstrDocu); + if (!!strDocu) + desc += '[' + strDocu + ']'; + desc += '\n'; +#endif + typeinfo->ReleaseVarDesc(vardesc); + } +} + +void MetaObjectGenerator::readInterfaceInfo() +{ + ITypeInfo *typeinfo = dispInfo; + if (!typeinfo) + return; + typeinfo->AddRef(); + int interface_serial = 0; + while (typeinfo) { + ushort nFuncs = 0; + ushort nVars = 0; + ushort nImpl = 0; + // get information about type + TYPEATTR *typeattr; + typeinfo->GetTypeAttr(&typeattr); + bool interesting = true; + if (typeattr) { + // get number of functions, variables, and implemented interfaces + nFuncs = typeattr->cFuncs; + nVars = typeattr->cVars; + nImpl = typeattr->cImplTypes; + + if ((typeattr->typekind == TKIND_DISPATCH || typeattr->typekind == TKIND_INTERFACE) && + (typeattr->guid != IID_IDispatch && typeattr->guid != IID_IUnknown)) { +#ifndef QAX_NO_CLASSINFO + if (d && d->useClassInfo) { + // UUID + QUuid uuid(typeattr->guid); + QString uuidstr = uuid.toString().toUpper(); + uuidstr = iidnames.value(QLatin1String("/Interface/") + uuidstr + QLatin1String("/Default"), uuidstr).toString(); + addClassInfo("Interface " + QByteArray::number(++interface_serial), uuidstr.toLatin1()); + } +#endif + typeinfo->ReleaseTypeAttr(typeattr); + } else { + interesting = false; + typeinfo->ReleaseTypeAttr(typeattr); + } + } + + if (interesting) { + readFuncsInfo(typeinfo, nFuncs); + readVarsInfo(typeinfo, nVars); + } + + if (!nImpl) { + typeinfo->Release(); + typeinfo = 0; + break; + } + + // go up one base class + HREFTYPE pRefType; + typeinfo->GetRefTypeOfImplType(0, &pRefType); + ITypeInfo *baseInfo = 0; + typeinfo->GetRefTypeInfo(pRefType, &baseInfo); + typeinfo->Release(); + if (typeinfo == baseInfo) { // IUnknown inherits IUnknown ??? + baseInfo->Release(); + typeinfo = 0; + break; + } + typeinfo = baseInfo; + } +} + +void MetaObjectGenerator::readEventInterface(ITypeInfo *eventinfo, IConnectionPoint *cpoint) +{ + TYPEATTR *eventattr; + eventinfo->GetTypeAttr(&eventattr); + if (!eventattr) + return; + if (eventattr->typekind != TKIND_DISPATCH) { + eventinfo->ReleaseTypeAttr(eventattr); + return; + } + + QAxEventSink *eventSink = 0; + if (d) { + IID conniid; + cpoint->GetConnectionInterface(&conniid); + eventSink = d->eventSink.value(QUuid(conniid)); + if (!eventSink) { + eventSink = new QAxEventSink(that); + d->eventSink.insert(QUuid(conniid), eventSink); + eventSink->advise(cpoint, conniid); + } + } + + // get information about all event functions + for (UINT fd = 0; fd < (UINT)eventattr->cFuncs; ++fd) { + FUNCDESC *funcdesc; + eventinfo->GetFuncDesc(fd, &funcdesc); + if (!funcdesc) + break; + if (funcdesc->invkind != INVOKE_FUNC || + funcdesc->funckind != FUNC_DISPATCH) { + eventinfo->ReleaseTypeAttr(eventattr); + eventinfo->ReleaseFuncDesc(funcdesc); + continue; + } + + QByteArray function; + QByteArray prototype; + QList<QByteArray> parameters; + + // parse event function description + BSTR bstrNames[256]; + UINT maxNames = 255; + UINT maxNamesOut; + eventinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut); + QList<QByteArray> names; + int p; + for (p = 0; p < (int)maxNamesOut; ++p) { + names << QString::fromWCharArray(bstrNames[p]).toLatin1(); + SysFreeString(bstrNames[p]); + } + + // get event function prototype + function = names.at(0); + QByteArray type; // dummy - we don't care about return values for signals + prototype = createPrototype(/*in*/ funcdesc, eventinfo, names, /*out*/type, parameters); + if (!hasSignal(prototype)) { + QByteArray pnames; + for (p = 0; p < parameters.count(); ++p) { + pnames += parameters.at(p); + if (p < parameters.count() - 1) + pnames += ','; + } + addSignal(prototype, pnames); + } + if (eventSink) + eventSink->addSignal(funcdesc->memid, prototype); + +#if 0 // documentation in metaobject would be cool? + // get function documentation + BSTR bstrDocu; + eventinfo->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0); + QString strDocu = QString::fromWCharArray(bstrDocu); + SysFreeString(bstrDocu); + if (!!strDocu) + desc += '[' + strDocu + ']'; + desc += '\n'; +#endif + eventinfo->ReleaseFuncDesc(funcdesc); + } + eventinfo->ReleaseTypeAttr(eventattr); +} + +void MetaObjectGenerator::readEventInfo() +{ + int event_serial = 0; + IConnectionPointContainer *cpoints = 0; + if (d && d->useEventSink) + d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints); + if (cpoints) { + // Get connection point enumerator + IEnumConnectionPoints *epoints = 0; + cpoints->EnumConnectionPoints(&epoints); + if (epoints) { + ULONG c = 1; + IConnectionPoint *cpoint = 0; + epoints->Reset(); + QList<QUuid> cpointlist; + do { + if (cpoint) cpoint->Release(); + cpoint = 0; + HRESULT hr = epoints->Next(c, &cpoint, &c); + if (!c || hr != S_OK) + break; + + IID conniid; + cpoint->GetConnectionInterface(&conniid); + // workaround for typelibrary bug of Word.Application + QUuid connuuid(conniid); + if (cpointlist.contains(connuuid)) + break; + +#ifndef QAX_NO_CLASSINFO + if (d->useClassInfo) { + QString uuidstr = connuuid.toString().toUpper(); + uuidstr = iidnames.value(QLatin1String("/Interface/") + uuidstr + QLatin1String("/Default"), uuidstr).toString(); + addClassInfo("Event Interface " + QByteArray::number(++event_serial), uuidstr.toLatin1()); + } +#endif + + // get information about type + if (conniid == IID_IPropertyNotifySink) { + // test whether property notify sink has been created already, and advise on it + QAxEventSink *eventSink = d->eventSink.value(iid_propNotifySink); + if (eventSink) + eventSink->advise(cpoint, conniid); + continue; + } + + ITypeInfo *eventinfo = 0; + if (typelib) + typelib->GetTypeInfoOfGuid(conniid, &eventinfo); + + if (eventinfo) { + // avoid recursion (see workaround above) + cpointlist.append(connuuid); + + readEventInterface(eventinfo, cpoint); + eventinfo->Release(); + } + } while (c); + if (cpoint) cpoint->Release(); + epoints->Release(); + } else if (classInfo) { // no enumeration - search source interfaces and ask for those + TYPEATTR *typeattr = 0; + classInfo->GetTypeAttr(&typeattr); + if (typeattr) { + for (int i = 0; i < typeattr->cImplTypes; ++i) { + int flags = 0; + classInfo->GetImplTypeFlags(i, &flags); + if (!(flags & IMPLTYPEFLAG_FSOURCE)) + continue; + HREFTYPE reference; + if (S_OK != classInfo->GetRefTypeOfImplType(i, &reference)) + continue; + ITypeInfo *eventInfo = 0; + classInfo->GetRefTypeInfo(reference, &eventInfo); + if (!eventInfo) + continue; + TYPEATTR *eventattr = 0; + eventInfo->GetTypeAttr(&eventattr); + if (eventattr) { + IConnectionPoint *cpoint = 0; + cpoints->FindConnectionPoint(eventattr->guid, &cpoint); + if (cpoint) { + if (eventattr->guid == IID_IPropertyNotifySink) { + // test whether property notify sink has been created already, and advise on it + QAxEventSink *eventSink = d->eventSink.value(iid_propNotifySink); + if (eventSink) + eventSink->advise(cpoint, eventattr->guid); + continue; + } + + readEventInterface(eventInfo, cpoint); + cpoint->Release(); + } + eventInfo->ReleaseTypeAttr(eventattr); + } + eventInfo->Release(); + } + classInfo->ReleaseTypeAttr(typeattr); + } + } + cpoints->Release(); + } +} + +QMetaObject *MetaObjectGenerator::tryCache() +{ + if (!cacheKey.isEmpty()) { + d->metaobj = mo_cache.value(cacheKey); + if (d->metaobj) { + d->cachedMetaObject = true; + + IConnectionPointContainer *cpoints = 0; + d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints); + if (cpoints) { + QList<QUuid>::ConstIterator it = d->metaobj->connectionInterfaces.begin(); + while (it != d->metaobj->connectionInterfaces.end()) { + QUuid iid = *it; + ++it; + + IConnectionPoint *cpoint = 0; + cpoints->FindConnectionPoint(iid, &cpoint); + if (cpoint) { + QAxEventSink *sink = new QAxEventSink(that); + sink->advise(cpoint, iid); + d->eventSink.insert(iid, sink); + sink->sigs = d->metaobj->sigs.value(iid); + sink->props = d->metaobj->props.value(iid); + sink->propsigs = d->metaobj->propsigs.value(iid); + cpoint->Release(); + } + } + cpoints->Release(); + } + + return d->metaobj; + } + } + return 0; +} + +QMetaObject *MetaObjectGenerator::metaObject(const QMetaObject *parentObject, const QByteArray &className) +{ + if (that) { + readClassInfo(); + if (typelib) { + BSTR bstr; + typelib->GetDocumentation(-1, &bstr, 0, 0, 0); + current_typelib = QString::fromWCharArray(bstr).toLatin1(); + SysFreeString(bstr); + } + if (d->tryCache && tryCache()) + return d->metaobj; + readEnumInfo(); + readInterfaceInfo(); + readEventInfo(); + } + + current_typelib = QByteArray(); + +#ifndef QAX_NO_CLASSINFO + if (!debugInfo.isEmpty() && d->useClassInfo) + addClassInfo("debugInfo", debugInfo); +#endif + + QAxMetaObject *metaobj = new QAxMetaObject; + + // revision + classname + table + zero terminator + uint int_data_size = 1+1+2+2+2+2+1; + + int_data_size += classinfo_list.count() * 2; + int_data_size += signal_list.count() * 5; + int_data_size += slot_list.count() * 5; + int_data_size += property_list.count() * 3; + int_data_size += enum_list.count() * 4; + for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin(); + it != enum_list.end(); ++it) { + int_data_size += (*it).count() * 2; + } + + uint *int_data = new uint[int_data_size]; + int_data[0] = 1; // revision number + int_data[1] = 0; // classname index + int_data[2] = classinfo_list.count(); // num_classinfo + int_data[3] = 10; // idx_classinfo + int_data[4] = signal_list.count() + slot_list.count(); // num_methods + int_data[5] = int_data[3] + int_data[2] * 2; // idx_signals + int_data[6] = property_list.count(); // num_properties + int_data[7] = int_data[5] + int_data[4] * 5; // idx_properties + int_data[8] = enum_list.count(); // num_enums + int_data[9] = int_data[7] + int_data[6] * 3; // idx_enums + int_data[int_data_size - 1] = 0; // eod; + + char null('\0'); + // data + zero-terminator + QByteArray stringdata = that ? QByteArray(that->className()) : className; + stringdata += null; + stringdata.reserve(8192); + + uint offset = int_data[3]; //idx_classinfo + + // each class info in form key\0value\0 + for (QMap<QByteArray, QByteArray>::ConstIterator it = classinfo_list.begin(); it != classinfo_list.end(); ++it) { + QByteArray key(it.key()); + QByteArray value(it.value()); + int_data[offset++] = stringdata.length(); + stringdata += key; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += value; + stringdata += null; + } + Q_ASSERT(offset == int_data[5]); + + // each signal in form prototype\0parameters\0type\0tag\0 + for (QMap<QByteArray, Method>::ConstIterator it = signal_list.begin(); it != signal_list.end(); ++it) { + QByteArray prototype(QMetaObject::normalizedSignature(it.key())); + QByteArray type(it.value().type); + QByteArray parameters(it.value().parameters); + if (!it.value().realPrototype.isEmpty()) + metaobj->realPrototype.insert(prototype, it.value().realPrototype); + QByteArray tag; + int flags = it.value().flags; + + int_data[offset++] = stringdata.length(); + stringdata += prototype; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += parameters; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += type; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += tag; + stringdata += null; + int_data[offset++] = flags; + } + + // each slot in form prototype\0parameters\0type\0tag\0 + for (QMap<QByteArray, Method>::ConstIterator it = slot_list.begin(); it != slot_list.end(); ++it) { + QByteArray prototype(QMetaObject::normalizedSignature(it.key())); + QByteArray type(it.value().type); + QByteArray parameters(it.value().parameters); + if (!it.value().realPrototype.isEmpty()) + metaobj->realPrototype.insert(prototype, it.value().realPrototype); + QByteArray tag; + int flags = it.value().flags; + + int_data[offset++] = stringdata.length(); + stringdata += prototype; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += parameters; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += type; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += tag; + stringdata += null; + int_data[offset++] = flags; + } + Q_ASSERT(offset == int_data[7]); + + // each property in form name\0type\0 + for (QMap<QByteArray, Property>::ConstIterator it = property_list.begin(); it != property_list.end(); ++it) { + QByteArray name(it.key()); + QByteArray type(it.value().type); + QByteArray realType(it.value().realType); + if (!realType.isEmpty() && realType != type) + metaobj->realPrototype.insert(name, realType); + uint flags = it.value().typeId; + + int_data[offset++] = stringdata.length(); + stringdata += name; + stringdata += null; + int_data[offset++] = stringdata.length(); + stringdata += type; + stringdata += null; + int_data[offset++] = flags; + } + Q_ASSERT(offset == int_data[9]); + + int value_offset = offset + enum_list.count() * 4; + // each enum in form name\0 + for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin(); it != enum_list.end(); ++it) { + QByteArray name(it.key()); + int flags = 0x0; // 0x1 for flag? + int count = it.value().count(); + + int_data[offset++] = stringdata.length(); + stringdata += name; + stringdata += null; + int_data[offset++] = flags; + int_data[offset++] = count; + int_data[offset++] = value_offset; + value_offset += count * 2; + } + Q_ASSERT(offset == int_data[9] + enum_list.count() * 4); + + // each enum value in form key\0 + for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin(); it != enum_list.end(); ++it) { + for (QList<QPair<QByteArray,int> >::ConstIterator it2 = it.value().begin(); it2 != it.value().end(); ++it2) { + QByteArray key((*it2).first); + int value = (*it2).second; + int_data[offset++] = stringdata.length(); + stringdata += key; + stringdata += null; + int_data[offset++] = value; + } + } + Q_ASSERT(offset == int_data_size-1); + + char *string_data = new char[stringdata.length()]; + memset(string_data, 0, sizeof(string_data)); + memcpy(string_data, stringdata, stringdata.length()); + + // put the metaobject together + metaobj->d.data = int_data; + metaobj->d.extradata = 0; + metaobj->d.stringdata = string_data; + metaobj->d.superdata = parentObject; + + if (d) + d->metaobj = metaobj; + + if (!cacheKey.isEmpty()) { + mo_cache.insert(cacheKey, d->metaobj); + d->cachedMetaObject = true; + for (QHash<QUuid, QAxEventSink*>::Iterator it = d->eventSink.begin(); it != d->eventSink.end(); ++it) { + QAxEventSink *sink = it.value(); + if (sink) { + QUuid ciid = sink->connectionInterface(); + + d->metaobj->connectionInterfaces.append(ciid); + d->metaobj->sigs.insert(ciid, sink->signalMap()); + d->metaobj->props.insert(ciid, sink->propertyMap()); + d->metaobj->propsigs.insert(ciid, sink->propSignalMap()); + } + } + } + + return metaobj; +} + +static const uint qt_meta_data_QAxBase[] = { + + // content: + 1, // revision + 0, // classname + 0, 0, // classinfo + 3, 10, // methods + 1, 25, // properties + 0, 0, // enums/sets + + // signals: signature, parameters, type, tag, flags + 24, 9, 8, 8, 0x05, + 55, 50, 8, 8, 0x05, + 102, 80, 8, 8, 0x05, + + // properties: name, type, flags + 149, 141, 0x0a095103, + + 0 // eod +}; + +static const char qt_meta_stringdata_QAxBase[] = { + "QAxBase\0\0name,argc,argv\0signal(QString,int,void*)\0name\0" + "propertyChanged(QString)\0code,source,desc,help\0" + "exception(int,QString,QString,QString)\0QString\0control\0" +}; + +static QMetaObject qaxobject_staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_QAxBase, + qt_meta_data_QAxBase, 0 } +}; +static QMetaObject qaxwidget_staticMetaObject = { + { &QWidget::staticMetaObject, qt_meta_stringdata_QAxBase, + qt_meta_data_QAxBase, 0 } +}; + +/*! + \internal + + The metaobject is generated on the fly from the information + provided by the IDispatch and ITypeInfo interface implementations + in the COM object. +*/ +const QMetaObject *QAxBase::metaObject() const +{ + if (d->metaobj) + return d->metaobj; + const QMetaObject* parentObject = parentMetaObject(); + + if (!d->ptr && !d->initialized) { + ((QAxBase*)this)->initialize(&d->ptr); + d->initialized = true; + } + +#ifndef QT_NO_THREAD + // only one thread at a time can generate meta objects + QMutexLocker locker(&cache_mutex); +#endif + + // return the default meta object if not yet initialized + if (!d->ptr || !d->useMetaObject) { + if (qObject()->isWidgetType()) + return &qaxwidget_staticMetaObject; + return &qaxobject_staticMetaObject; + } + MetaObjectGenerator generator((QAxBase*)this, d); + return generator.metaObject(parentObject); +} + +/*! + \internal + + Connects to all event interfaces of the object. + + Called by the subclasses' connectNotify() reimplementations, so + at this point the connection as actually been created already. +*/ +void QAxBase::connectNotify() +{ + if (d->eventSink.count()) // already listening + return; + + IEnumConnectionPoints *epoints = 0; + if (d->ptr && d->useEventSink) { + IConnectionPointContainer *cpoints = 0; + d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints); + if (!cpoints) + return; + + cpoints->EnumConnectionPoints(&epoints); + cpoints->Release(); + } + + if (!epoints) + return; + + UINT index; + IDispatch *disp = d->dispatch(); + ITypeInfo *typeinfo = 0; + ITypeLib *typelib = 0; + if (disp) + disp->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo); + if (typeinfo) + typeinfo->GetContainingTypeLib(&typelib, &index); + + if (!typelib) { + epoints->Release(); + return; + } + + MetaObjectGenerator generator(this, d); + bool haveEnumInfo = false; + + ULONG c = 1; + IConnectionPoint *cpoint = 0; + epoints->Reset(); + do { + if (cpoint) cpoint->Release(); + cpoint = 0; + epoints->Next(c, &cpoint, &c); + if (!c || !cpoint) + break; + + IID conniid; + cpoint->GetConnectionInterface(&conniid); + // workaround for typelibrary bug of Word.Application + QString connuuid(QUuid(conniid).toString()); + if (d->eventSink.contains(connuuid)) + break; + + // Get ITypeInfo for source-interface, and skip if not supporting IDispatch + ITypeInfo *eventinfo = 0; + typelib->GetTypeInfoOfGuid(conniid, &eventinfo); + if (eventinfo) { + TYPEATTR *eventAttr; + eventinfo->GetTypeAttr(&eventAttr); + if (!eventAttr) { + eventinfo->Release(); + break; + } + + TYPEKIND eventKind = eventAttr->typekind; + eventinfo->ReleaseTypeAttr(eventAttr); + if (eventKind != TKIND_DISPATCH) { + eventinfo->Release(); + break; + } + } + + // always into the cache to avoid recoursion + QAxEventSink *eventSink = eventinfo ? new QAxEventSink(this) : 0; + d->eventSink.insert(connuuid, eventSink); + + if (!eventinfo) + continue; + + // have to get type info to support signals with enum parameters + if (!haveEnumInfo) { + bool wasTryCache = d->tryCache; + d->tryCache = true; + generator.readClassInfo(); + generator.readEnumInfo(); + d->tryCache = wasTryCache; + haveEnumInfo = true; + } + generator.readEventInterface(eventinfo, cpoint); + eventSink->advise(cpoint, conniid); + + eventinfo->Release(); + } while (c); + if (cpoint) cpoint->Release(); + epoints->Release(); + + typelib->Release(); + + // make sure we don't try again + if (!d->eventSink.count()) + d->eventSink.insert(QString(), 0); +} + +/*! + \fn QString QAxBase::generateDocumentation() + + Returns a rich text string with documentation for the + wrapped COM object. Dump the string to an HTML-file, + or use it in e.g. a QTextBrowser widget. +*/ + +static bool checkHRESULT(HRESULT hres, EXCEPINFO *exc, QAxBase *that, const QString &name, uint argerr) +{ + switch(hres) { + case S_OK: + return true; + case DISP_E_BADPARAMCOUNT: + qWarning("QAxBase: Error calling IDispatch member %s: Bad parameter count", name.toLatin1().data()); + return false; + case DISP_E_BADVARTYPE: + qWarning("QAxBase: Error calling IDispatch member %s: Bad variant type", name.toLatin1().data()); + return false; + case DISP_E_EXCEPTION: + { + bool printWarning = true; + unsigned short code = -1; + QString source, desc, help; + const QMetaObject *mo = that->metaObject(); + int exceptionSignal = mo->indexOfSignal("exception(int,QString,QString,QString)"); + if (exceptionSignal >= 0) { + if (exc->pfnDeferredFillIn) + exc->pfnDeferredFillIn(exc); + + code = exc->wCode ? exc->wCode : exc->scode; + source = QString::fromWCharArray(exc->bstrSource); + desc = QString::fromWCharArray(exc->bstrDescription); + help = QString::fromWCharArray(exc->bstrHelpFile); + uint helpContext = exc->dwHelpContext; + + if (helpContext && !help.isEmpty()) + help += QString::fromLatin1(" [%1]").arg(helpContext); + + if (QAxEventSink::signalHasReceivers(that->qObject(), "exception(int,QString,QString,QString)")) { + void *argv[] = {0, &code, &source, &desc, &help}; + that->qt_metacall(QMetaObject::InvokeMetaMethod, exceptionSignal, argv); + printWarning = false; + } + } + if (printWarning) { + qWarning("QAxBase: Error calling IDispatch member %s: Exception thrown by server", name.toLatin1().data()); + qWarning(" Code : %d", code); + qWarning(" Source : %s", source.toLatin1().data()); + qWarning(" Description: %s", desc.toLatin1().data()); + qWarning(" Help : %s", help.toLatin1().data()); + qWarning(" Connect to the exception(int,QString,QString,QString) signal to catch this exception"); + } + } + return false; + case DISP_E_MEMBERNOTFOUND: + qWarning("QAxBase: Error calling IDispatch member %s: Member not found", name.toLatin1().data()); + return false; + case DISP_E_NONAMEDARGS: + qWarning("QAxBase: Error calling IDispatch member %s: No named arguments", name.toLatin1().data()); + return false; + case DISP_E_OVERFLOW: + qWarning("QAxBase: Error calling IDispatch member %s: Overflow", name.toLatin1().data()); + return false; + case DISP_E_PARAMNOTFOUND: + qWarning("QAxBase: Error calling IDispatch member %s: Parameter %d not found", name.toLatin1().data(), argerr); + return false; + case DISP_E_TYPEMISMATCH: + qWarning("QAxBase: Error calling IDispatch member %s: Type mismatch in parameter %d", name.toLatin1().data(), argerr); + return false; + case DISP_E_UNKNOWNINTERFACE: + qWarning("QAxBase: Error calling IDispatch member %s: Unknown interface", name.toLatin1().data()); + return false; + case DISP_E_UNKNOWNLCID: + qWarning("QAxBase: Error calling IDispatch member %s: Unknown locale ID", name.toLatin1().data()); + return false; + case DISP_E_PARAMNOTOPTIONAL: + qWarning("QAxBase: Error calling IDispatch member %s: Non-optional parameter missing", name.toLatin1().data()); + return false; + default: + qWarning("QAxBase: Error calling IDispatch member %s: Unknown error", name.toLatin1().data()); + return false; + } +} + +/*! + \internal +*/ +int QAxBase::internalProperty(QMetaObject::Call call, int index, void **v) +{ + const QMetaObject *mo = metaObject(); + const QMetaProperty prop = mo->property(index + mo->propertyOffset()); + QByteArray propname = prop.name(); + + // hardcoded control property + if (propname == "control") { + switch(call) { + case QMetaObject::ReadProperty: + *(QString*)*v = control(); + break; + case QMetaObject::WriteProperty: + setControl(*(QString*)*v); + break; + case QMetaObject::ResetProperty: + clear(); + break; + default: + break; + } + return index - mo->propertyCount(); + } + + // get the IDispatch + if (!d->ptr || !prop.isValid()) + return index; + IDispatch *disp = d->dispatch(); + if (!disp) + return index; + + DISPID dispid = d->metaObject()->dispIDofName(propname, disp); + if (dispid == DISPID_UNKNOWN) + return index; + + Q_ASSERT(d->metaobj); + // property found, so everthing that goes wrong now should not bother the caller + index -= mo->propertyCount(); + + VARIANTARG arg; + VariantInit(&arg); + DISPPARAMS params; + EXCEPINFO excepinfo; + memset(&excepinfo, 0, sizeof(excepinfo)); + UINT argerr = 0; + HRESULT hres = E_FAIL; + + QByteArray proptype(prop.typeName()); + switch (call) { + case QMetaObject::ReadProperty: + { + params.cArgs = 0; + params.cNamedArgs = 0; + params.rgdispidNamedArgs = 0; + params.rgvarg = 0; + + hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &arg, &excepinfo, 0); + + // map result VARIANTARG to void* + uint type = QVariant::Int; + if (!prop.isEnumType()) + type = prop.type(); + QVariantToVoidStar(VARIANTToQVariant(arg, proptype, type), *v, proptype, type); + if ((arg.vt != VT_DISPATCH && arg.vt != VT_UNKNOWN) || type == QVariant::Pixmap || type == QVariant::Font) + clearVARIANT(&arg); + } + break; + + case QMetaObject::WriteProperty: + { + QVariant::Type t = (QVariant::Type)prop.type(); + + DISPID dispidNamed = DISPID_PROPERTYPUT; + params.cArgs = 1; + params.cNamedArgs = 1; + params.rgdispidNamedArgs = &dispidNamed; + params.rgvarg = &arg; + + arg.vt = VT_ERROR; + arg.scode = DISP_E_TYPEMISMATCH; + + // map void* to VARIANTARG via QVariant + QVariant qvar; + if (prop.isEnumType()) { + qvar = *(int*)v[0]; + proptype = 0; + } else { + if (t == QVariant::LastType) { + qvar = *(QVariant*)v[0]; + proptype = 0; + } else if (t == QVariant::UserType) { + qvar = QVariant(qRegisterMetaType<void*>(prop.typeName()), (void**)v[0]); +// qvar.setValue(*(void**)v[0], prop.typeName()); + } else { + proptype = d->metaObject()->propertyType(propname); + qvar = QVariant(t, v[0]); + } + } + + QVariantToVARIANT(qvar, arg, proptype); + if (arg.vt == VT_EMPTY || arg.vt == VT_ERROR) { + qWarning("QAxBase::setProperty: Unhandled property type %s", prop.typeName()); + break; + } + } + hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, 0, &excepinfo, &argerr); + clearVARIANT(&arg); + break; + + default: + break; + } + + checkHRESULT(hres, &excepinfo, this, QLatin1String(propname), argerr); + return index; +} + +int QAxBase::internalInvoke(QMetaObject::Call call, int index, void **v) +{ + Q_ASSERT(call == QMetaObject::InvokeMetaMethod); + Q_UNUSED(call); + + // get the IDispatch + IDispatch *disp = d->dispatch(); + if (!disp) + return index; + + const QMetaObject *mo = metaObject(); + // get the slot information + const QMetaMethod slot = mo->method(index + mo->methodOffset()); + Q_ASSERT(slot.methodType() == QMetaMethod::Slot); + + QByteArray signature(slot.signature()); + QByteArray slotname(signature); + slotname.truncate(slotname.indexOf('(')); + + // Get the Dispatch ID of the method to be called + bool isProperty = false; + DISPID dispid = d->metaObject()->dispIDofName(slotname, disp); + + Q_ASSERT(d->metaobj); + + if (dispid == DISPID_UNKNOWN && slotname.toLower().startsWith("set")) { + // see if we are calling a property set function as a slot + slotname = slotname.right(slotname.length() - 3); + dispid = d->metaobj->dispIDofName(slotname, disp); + isProperty = true; + } + if (dispid == DISPID_UNKNOWN) + return index; + + // slot found, so everthing that goes wrong now should not bother the caller + index -= mo->methodCount(); + + // setup the parameters + DISPPARAMS params; + DISPID dispidNamed = DISPID_PROPERTYPUT; + params.cArgs = d->metaobj->numParameter(signature); + params.cNamedArgs = isProperty ? 1 : 0; + params.rgdispidNamedArgs = isProperty ? &dispidNamed : 0; + params.rgvarg = 0; + VARIANTARG static_rgvarg[QAX_NUM_PARAMS]; + if (params.cArgs) { + if (params.cArgs <= QAX_NUM_PARAMS) + params.rgvarg = static_rgvarg; + else + params.rgvarg = new VARIANTARG[params.cArgs]; + } + + int p; + for (p = 0; p < (int)params.cArgs; ++p) { + bool out; + QByteArray type = d->metaobj->paramType(signature, p, &out); + QVariant::Type vt = QVariant::nameToType(type); + QVariant qvar; + if (vt != QVariant::UserType) + qvar = QVariant(vt, v[p + 1]); + + if (!qvar.isValid()) { + if (type == "IDispatch*") + qvar.setValue(*(IDispatch**)v[p+1]); + else if (type == "IUnknown*") + qvar.setValue(*(IUnknown**)v[p+1]); + else if (type == "QVariant") + qvar = *(QVariant*)v[p + 1]; + else if (mo->indexOfEnumerator(type) != -1) + qvar = *(int*)v[p + 1]; + else + qvar = QVariant(QMetaType::type(type), v[p + 1]); + } + + QVariantToVARIANT(qvar, params.rgvarg[params.cArgs - p - 1], type, out); + } + + // call the method + VARIANT ret; + VariantInit(&ret); + UINT argerr = 0; + HRESULT hres = E_FAIL; + EXCEPINFO excepinfo; + memset(&excepinfo, 0, sizeof(excepinfo)); + + WORD wFlags = isProperty ? DISPATCH_PROPERTYPUT : DISPATCH_METHOD | DISPATCH_PROPERTYGET; + hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, wFlags, ¶ms, &ret, &excepinfo, &argerr); + + // get return value + if (hres == S_OK && ret.vt != VT_EMPTY) + QVariantToVoidStar(VARIANTToQVariant(ret, slot.typeName()), v[0], slot.typeName()); + + // update out parameters + for (p = 0; p < (int)params.cArgs; ++p) { + bool out; + QByteArray ptype = d->metaobj->paramType(signature, p, &out); + if (out) + QVariantToVoidStar(VARIANTToQVariant(params.rgvarg[params.cArgs - p - 1], ptype), v[p+1], ptype); + } + // clean up + for (p = 0; p < (int)params.cArgs; ++p) + clearVARIANT(params.rgvarg+p); + if (params.rgvarg != static_rgvarg) + delete [] params.rgvarg; + + checkHRESULT(hres, &excepinfo, this, QString::fromLatin1(slotname), params.cArgs-argerr-1); + return index; +} + +/*! + \internal +*/ +int QAxBase::qt_metacall(QMetaObject::Call call, int id, void **v) +{ + const QMetaObject *mo = metaObject(); + if (isNull() && mo->property(id + mo->propertyOffset()).name() != QByteArray("control")) { + qWarning("QAxBase::qt_metacall: Object is not initialized, or initialization failed"); + return id; + } + + switch(call) { + case QMetaObject::InvokeMetaMethod: + switch (mo->method(id + mo->methodOffset()).methodType()) { + case QMetaMethod::Signal: + QMetaObject::activate(qObject(), mo, id, v); + id -= mo->methodCount(); + break; + case QMetaMethod::Method: + case QMetaMethod::Slot: + id = internalInvoke(call, id, v); + break; + default: + break; + } + break; + case QMetaObject::ReadProperty: + case QMetaObject::WriteProperty: + case QMetaObject::ResetProperty: + id = internalProperty(call, id, v); + break; + case QMetaObject::QueryPropertyScriptable: + case QMetaObject::QueryPropertyDesignable: + case QMetaObject::QueryPropertyStored: + case QMetaObject::QueryPropertyEditable: + case QMetaObject::QueryPropertyUser: + id -= mo->propertyCount(); + break; + default: + break; + } + Q_ASSERT(id < 0); + return id; +} + +#ifdef QT_CHECK_STATE +static void qax_noSuchFunction(int disptype, const QByteArray &name, const QByteArray &function, const QAxBase *that) +{ + const QMetaObject *metaObject = that->metaObject(); + const char *coclass = metaObject->classInfo(metaObject->indexOfClassInfo("CoClass")).value(); + + if (disptype == DISPATCH_METHOD) { + qWarning("QAxBase::dynamicCallHelper: %s: No such method in %s [%s]", name.data(), that->control().toLatin1().data(), coclass ? coclass: "unknown"); + qWarning("\tCandidates are:"); + for (int i = 0; i < metaObject->methodCount(); ++i) { + const QMetaMethod slot(metaObject->method(i)); + if (slot.methodType() != QMetaMethod::Slot) + continue; + QByteArray signature = slot.signature(); + if (signature.toLower().startsWith(function.toLower())) + qWarning("\t\t%s", signature.data()); + } + } else { + qWarning("QAxBase::dynamicCallHelper: %s: No such property in %s [%s]", name.data(), that->control().toLatin1().data(), coclass ? coclass: "unknown"); + if (!function.isEmpty()) { + qWarning("\tCandidates are:"); + char f0 = function.toLower().at(0); + for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) { + QByteArray signature(metaObject->property(i).name()); + if (!signature.isEmpty() && signature.toLower().at(0) == f0) + qWarning("\t\t%s", signature.data()); + } + } + } +} +#endif + +/*! + \internal + + \a name is already normalized? +*/ +bool QAxBase::dynamicCallHelper(const char *name, void *inout, QList<QVariant> &vars, QByteArray &type) +{ + if (isNull()) { + qWarning("QAxBase::dynamicCallHelper: Object is not initialized, or initialization failed"); + return false; + } + + IDispatch *disp = d->dispatch(); + if (!disp) { + qWarning("QAxBase::dynamicCallHelper: Object does not support automation"); + return false; + } + + const QMetaObject *mo = metaObject(); + d->metaObject(); + Q_ASSERT(d->metaobj); + + int varc = vars.count(); + + QByteArray normFunction = QMetaObject::normalizedSignature(name); + QByteArray function(normFunction); + VARIANT staticarg[QAX_NUM_PARAMS]; + VARIANT *arg = 0; + VARIANTARG *res = (VARIANTARG*)inout; + + unsigned short disptype; + + int id = -1; + bool parse = false; + + if (function.contains('(')) { + disptype = DISPATCH_METHOD | DISPATCH_PROPERTYGET; + if (d->useMetaObject) + id = mo->indexOfSlot(function); + if (id >= 0) { + const QMetaMethod slot = mo->method(id); + Q_ASSERT(slot.methodType() == QMetaMethod::Slot); + function = slot.signature(); + type = slot.typeName(); + } + function.truncate(function.indexOf('(')); + parse = !varc && normFunction.length() > function.length() + 2; + if (parse) { + QString args = QLatin1String(normFunction); + args = args.mid(function.length() + 1); + // parse argument string int list of arguments + QString curArg; + const QChar *c = args.unicode(); + int index = 0; + bool inString = false; + bool inEscape = false; + while (index < (int)args.length()) { + QChar cc = *c; + ++c; + ++index; + switch(cc.toLatin1()) { + case 'n': + if (inEscape) + cc = QLatin1Char('\n'); + break; + case 'r': + if (inEscape) + cc = QLatin1Char('\r'); + break; + case 't': + if (inEscape) + cc = QLatin1Char('\t'); + break; + case '\\': + if (!inEscape && inString) { + inEscape = true; + continue; + } + break; + case '"': + if (!inEscape) { + inString = !inString; + curArg += cc; + continue; + } + break; + case ' ': + if (!inString && curArg.isEmpty()) + continue; + break; + case ',': + case ')': + if (inString) + break; + curArg = curArg.trimmed(); + if (curArg.at(0) == QLatin1Char('\"') && curArg.at(curArg.length()-1) == QLatin1Char('\"')) { + vars << curArg.mid(1, curArg.length() - 2); + } else { + bool isNumber = false; + bool isDouble = false; + int number = curArg.toInt(&isNumber); + double dbl = curArg.toDouble(&isDouble); + if (isNumber) { + vars << number; + } else if (isDouble) { + vars << dbl; + } else { + bool isEnum = false; + for (int enumIndex = 0; enumIndex < mo->enumeratorCount(); ++enumIndex) { + QMetaEnum metaEnum =mo->enumerator(enumIndex); + int value = metaEnum.keyToValue(curArg.toLatin1()); + if (value != -1 && !QByteArray(metaEnum.valueToKey(value)).isEmpty()) { + vars << value; + isEnum = true; + break; + } + } + if (!isEnum) + vars << curArg; + } + } + curArg.clear(); + continue; + default: + break; + } + inEscape = false; + curArg += cc; + } + + varc = vars.count(); + } + } else { + if (d->useMetaObject) + id = mo->indexOfProperty(normFunction); + + if (id >= 0) { + const QMetaProperty prop =mo->property(id); + type = prop.typeName(); + } + if (varc == 1) { + res = 0; + disptype = DISPATCH_PROPERTYPUT; + } else { + disptype = DISPATCH_PROPERTYGET; + } + } + if (varc) { + varc = qMin(varc, d->metaobj->numParameter(normFunction)); + arg = varc <= QAX_NUM_PARAMS ? staticarg : new VARIANT[varc]; + for (int i = 0; i < varc; ++i) { + QVariant var(vars.at(i)); + VariantInit(arg + (varc - i - 1)); + bool out = false; + QByteArray paramType; + if (disptype == DISPATCH_PROPERTYPUT) + paramType = type; + else if (parse || disptype == DISPATCH_PROPERTYGET) + paramType = 0; + else + paramType = d->metaobj->paramType(normFunction, i, &out); + + if ((!parse && d->useMetaObject && var.type() == QVariant::String) || var.type() == QVariant::ByteArray) { + int enumIndex =mo->indexOfEnumerator(paramType); + if (enumIndex != -1) { + QMetaEnum metaEnum =mo->enumerator(enumIndex); + QVariantToVARIANT(metaEnum.keyToValue(var.toByteArray()), arg[varc - i - 1], "int", out); + } + } + + if (arg[varc - i - 1].vt == VT_EMPTY) + QVariantToVARIANT(var, arg[varc - i - 1], paramType, out); + } + } + + DISPID dispid = d->metaobj->dispIDofName(function, disp); + if (dispid == DISPID_UNKNOWN && function.toLower().startsWith("set")) { + function = function.mid(3); + dispid = d->metaobj->dispIDofName(function, disp); + disptype = DISPATCH_PROPERTYPUT; + } + + if (dispid == DISPID_UNKNOWN) { +#ifdef QT_CHECK_STATE + qax_noSuchFunction(disptype, normFunction, function, this); +#endif + return false; + } + + DISPPARAMS params; + DISPID dispidNamed = DISPID_PROPERTYPUT; + + params.cArgs = varc; + params.cNamedArgs = (disptype == DISPATCH_PROPERTYPUT) ? 1 : 0; + params.rgdispidNamedArgs = (disptype == DISPATCH_PROPERTYPUT) ? &dispidNamed : 0; + params.rgvarg = arg; + EXCEPINFO excepinfo; + memset(&excepinfo, 0, sizeof(excepinfo)); + UINT argerr = 0; + + HRESULT hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, disptype, ¶ms, res, &excepinfo, &argerr); + + if (disptype == (DISPATCH_METHOD|DISPATCH_PROPERTYGET) && hres == S_OK && varc) { + for (int i = 0; i < varc; ++i) + if (arg[varc-i-1].vt & VT_BYREF) // update out-parameters + vars[i] = VARIANTToQVariant(arg[varc-i-1], vars.at(i).typeName()); + } + + // clean up + for (int i = 0; i < varc; ++i) + clearVARIANT(params.rgvarg+i); + if (arg && arg != staticarg) + delete[] arg; + + return checkHRESULT(hres, &excepinfo, this, QLatin1String(function), varc-argerr-1); +} + + +/*! + Calls the COM object's method \a function, passing the + parameters \a var1, \a var1, \a var2, \a var3, \a var4, \a var5, + \a var6, \a var7 and \a var8, and returns the value returned by + the method, or an invalid QVariant if the method does not return + a value or when the function call failed. + + If \a function is a method of the object the string must be provided + as the full prototype, for example as it would be written in a + QObject::connect() call. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 15 + + Alternatively a function can be called passing the parameters embedded + in the string, e.g. above function can also be invoked using + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 16 + + All parameters are passed as strings; it depends on the control whether + they are interpreted correctly, and is slower than using the prototype + with correctly typed parameters. + + If \a function is a property the string has to be the name of the + property. The property setter is called when \a var1 is a valid QVariant, + otherwise the getter is called. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 17 + + Note that it is faster to get and set properties using + QObject::property() and QObject::setProperty(). + + dynamicCall() can also be used to call objects with a + \l{QAxBase::disableMetaObject()}{disabled metaobject} wrapper, + which can improve performance significantely, esp. when calling many + different objects of different types during an automation process. + ActiveQt will then however not validate parameters. + + It is only possible to call functions through dynamicCall() that + have parameters or return values of datatypes supported by + QVariant. See the QAxBase class documentation for a list of + supported and unsupported datatypes. If you want to call functions + that have unsupported datatypes in the parameter list, use + queryInterface() to retrieve the appropriate COM interface, and + use the function directly. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 18 + + This is also more efficient. +*/ +QVariant QAxBase::dynamicCall(const char *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) +{ + QList<QVariant> vars; + QVariant var = var1; + int argc = 1; + while(var.isValid()) { + vars << var; + switch(++argc) { + case 2: var = var2; break; + case 3: var = var3; break; + case 4: var = var4; break; + case 5: var = var5; break; + case 6: var = var6; break; + case 7: var = var7; break; + case 8: var = var8; break; + default:var = QVariant(); break; + } + } + + return dynamicCall(function, vars); +} + +/*! + \overload + + Calls the COM object's method \a function, passing the + parameters in \a vars, and returns the value returned by + the method. If the method does not return a value or when + the function call failed this function returns an invalid + QVariant object. + + The QVariant objects in \a vars are updated when the method has + out-parameters. +*/ +QVariant QAxBase::dynamicCall(const char *function, QList<QVariant> &vars) +{ + VARIANTARG res; + VariantInit(&res); + + QByteArray rettype; + if (!dynamicCallHelper(function, &res, vars, rettype)) + return QVariant(); + + QVariant qvar = VARIANTToQVariant(res, rettype); + if ((res.vt != VT_DISPATCH && res.vt != VT_UNKNOWN) || qvar.type() == QVariant::Pixmap || qvar.type() == QVariant::Font) + clearVARIANT(&res); + + return qvar; +} + +/*! + Returns a pointer to a QAxObject wrapping the COM object provided + by the method or property \a name, passing passing the parameters + \a var1, \a var1, \a var2, \a var3, \a var4, \a var5, \a var6, + \a var7 and \a var8. + + If \a name is provided by a method the string must include the + full function prototype. + + If \a name is a property the string must be the name of the property, + and \a var1, ... \a var8 are ignored. + + The returned QAxObject is a child of this object (which is either of + type QAxObject or QAxWidget), and is deleted when this object is + deleted. It is however safe to delete the returned object yourself, + and you should do so when you iterate over lists of subobjects. + + COM enabled applications usually have an object model publishing + certain elements of the application as dispatch interfaces. Use + this method to navigate the hierarchy of the object model, e.g. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 19 +*/ +QAxObject *QAxBase::querySubObject(const char *name, + const QVariant &var1, + const QVariant &var2, + const QVariant &var3, + const QVariant &var4, + const QVariant &var5, + const QVariant &var6, + const QVariant &var7, + const QVariant &var8) +{ + QList<QVariant> vars; + QVariant var = var1; + int argc = 1; + while(var.isValid()) { + vars << var; + switch(++argc) { + case 2: var = var2; break; + case 3: var = var3; break; + case 4: var = var4; break; + case 5: var = var5; break; + case 6: var = var6; break; + case 7: var = var7; break; + case 8: var = var8; break; + default:var = QVariant(); break; + } + } + + return querySubObject(name, vars); +} + +/*! + \overload + + The QVariant objects in \a vars are updated when the method has + out-parameters. +*/ +QAxObject *QAxBase::querySubObject(const char *name, QList<QVariant> &vars) +{ + QAxObject *object = 0; + VARIANTARG res; + VariantInit(&res); + + QByteArray rettype; + if (!dynamicCallHelper(name, &res, vars, rettype)) + return 0; + + switch (res.vt) { + case VT_DISPATCH: + if (res.pdispVal) { + if (rettype.isEmpty() || rettype == "IDispatch*" || rettype == "QVariant") { + object = new QAxObject(res.pdispVal, qObject()); + } else if (QMetaType::type(rettype)) { + QVariant qvar = VARIANTToQVariant(res, rettype, 0); + object = *(QAxObject**)qvar.constData(); +// qVariantGet(qvar, object, rettype); + res.pdispVal->AddRef(); + } + if (object) + ((QAxBase*)object)->d->tryCache = true; + } + break; + case VT_UNKNOWN: + if (res.punkVal) { + if (rettype.isEmpty() || rettype == "IUnknown*") { + object = new QAxObject(res.punkVal, qObject()); + } else if (QMetaType::type(rettype)) { + QVariant qvar = VARIANTToQVariant(res, rettype, 0); + object = *(QAxObject**)qvar.constData(); +// qVariantGet(qvar, object, rettype); + res.punkVal->AddRef(); + } + if (object) + ((QAxBase*)object)->d->tryCache = true; + } + break; + case VT_EMPTY: +#ifdef QT_CHECK_STATE + { + const char *coclass = metaObject()->classInfo(metaObject()->indexOfClassInfo("CoClass")).value(); + qWarning("QAxBase::querySubObject: %s: Error calling function or property in %s (%s)" + , name, control().toLatin1().data(), coclass ? coclass: "unknown"); + } +#endif + break; + default: +#ifdef QT_CHECK_STATE + { + const char *coclass = metaObject()->classInfo(metaObject()->indexOfClassInfo("CoClass")).value(); + qWarning("QAxBase::querySubObject: %s: Method or property is not of interface type in %s (%s)" + , name, control().toLatin1().data(), coclass ? coclass: "unknown"); + } +#endif + break; + } + + clearVARIANT(&res); + return object; +} + +class QtPropertyBag : public IPropertyBag +{ +public: + QtPropertyBag() :ref(0) {} + virtual ~QtPropertyBag() {} + + HRESULT __stdcall QueryInterface(REFIID iid, LPVOID *iface) + { + *iface = 0; + if (iid == IID_IUnknown) + *iface = this; + else if (iid == IID_IPropertyBag) + *iface = this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; + } + unsigned long __stdcall AddRef() { return ++ref; } + unsigned long __stdcall Release() + { + if (!--ref) { + delete this; + return 0; + } + return ref; + } + + HRESULT __stdcall Read(LPCOLESTR name, VARIANT *var, IErrorLog *) + { + if (!var) + return E_POINTER; + + QString property = QString::fromWCharArray(name); + QVariant qvar = map.value(property); + QVariantToVARIANT(qvar, *var); + return S_OK; + } + HRESULT __stdcall Write(LPCOLESTR name, VARIANT *var) + { + if (!var) + return E_POINTER; + QString property = QString::fromWCharArray(name); + QVariant qvar = VARIANTToQVariant(*var, 0); + map[property] = qvar; + + return S_OK; + } + + QAxBase::PropertyBag map; + +private: + unsigned long ref; +}; + +/*! + Returns a name:value map of all the properties exposed by the COM + object. + + This is more efficient than getting multiple properties + individually if the COM object supports property bags. + + \warning It is not guaranteed that the property bag implementation + of the COM object returns all properties, or that the properties + returned are the same as those available through the IDispatch + interface. +*/ +QAxBase::PropertyBag QAxBase::propertyBag() const +{ + PropertyBag result; + + if (!d->ptr && !d->initialized) { + ((QAxBase*)this)->initialize(&d->ptr); + d->initialized = true; + } + + if (isNull()) + return result; + IPersistPropertyBag *persist = 0; + d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist); + if (persist) { + QtPropertyBag *pbag = new QtPropertyBag(); + pbag->AddRef(); + persist->Save(pbag, false, true); + result = pbag->map; + pbag->Release(); + persist->Release(); + return result; + } else { + const QMetaObject *mo = metaObject(); + for (int p = mo->propertyOffset(); p < mo->propertyCount(); ++p) { + const QMetaProperty property = mo->property(p); + QVariant var = qObject()->property(property.name()); + result.insert(QLatin1String(property.name()), var); + } + } + return result; +} + +/*! + Sets the properties of the COM object to the corresponding values + in \a bag. + + \warning + You should only set property bags that have been returned by the + propertyBag function, as it cannot be guaranteed that the property + bag implementation of the COM object supports the same properties + that are available through the IDispatch interface. + + \sa propertyBag() +*/ +void QAxBase::setPropertyBag(const PropertyBag &bag) +{ + if (!d->ptr && !d->initialized) { + initialize(&d->ptr); + d->initialized = true; + } + + if (isNull()) + return; + IPersistPropertyBag *persist = 0; + d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist); + if (persist) { + QtPropertyBag *pbag = new QtPropertyBag(); + pbag->map = bag; + pbag->AddRef(); + persist->Load(pbag, 0); + pbag->Release(); + persist->Release(); + } else { + const QMetaObject *mo = metaObject(); + for (int p = mo->propertyOffset(); p < mo->propertyCount(); ++p) { + const QMetaProperty property = mo->property(p); + QVariant var = bag.value(QLatin1String(property.name())); + qObject()->setProperty(property.name(), var); + } + } +} + +/*! + Returns true if the property \a prop is writable; otherwise + returns false. By default, all properties are writable. + + \warning + Depending on the control implementation this setting might be + ignored for some properties. + + \sa setPropertyWritable(), propertyChanged() +*/ +bool QAxBase::propertyWritable(const char *prop) const +{ + return d->propWritable.value(prop, true); +} + +/*! + Sets the property \a prop to writable if \a ok is true, otherwise + sets \a prop to be read-only. By default, all properties are + writable. + + \warning + Depending on the control implementation this setting might be + ignored for some properties. + + \sa propertyWritable(), propertyChanged() +*/ +void QAxBase::setPropertyWritable(const char *prop, bool ok) +{ + d->propWritable[prop] = ok; +} + +/*! + Returns true if there is no COM object loaded by this wrapper; + otherwise return false. + + \sa control +*/ +bool QAxBase::isNull() const +{ + return !d->ptr; +} + +/*! + Returns a QVariant that wraps the COM object. The variant can + then be used as a parameter in e.g. dynamicCall(). +*/ +QVariant QAxBase::asVariant() const +{ + if (!d->ptr && !d->initialized) { + ((QAxBase*)this)->initialize(&d->ptr); + d->initialized = true; + } + + QVariant qvar; + QByteArray cn(className()); + if (cn == "QAxObject" || cn == "QAxWidget" || cn == "QAxBase") { + if (d->dispatch()) + qvar.setValue(d->dispatch()); + else if (d->ptr) + qvar.setValue(d->ptr); + } else { + cn = cn.mid(cn.lastIndexOf(':') + 1); + QObject *object = qObject(); + if (QMetaType::type(cn)) + qvar = QVariant(qRegisterMetaType<QObject*>(cn + '*'), &object); +// qvar.setValue(qObject(), cn + '*'); + } + + return qvar; +} + +// internal function that creates a QAxObject from an iface +// used by type-conversion code (types.cpp) +void *qax_createObjectWrapper(int metaType, IUnknown *iface) +{ + if (!iface) + return 0; + + QAxObject *object = (QAxObject*)QMetaType::construct(metaType, 0); + QAxBasePrivate *d = object->d; + + d->ptr = iface; + d->initialized = true; + + // no release, since no addref + + return object; +} + +/*! + \fn void QAxBase::signal(const QString &name, int argc, void *argv) + + This generic signal gets emitted when the COM object issues the + event \a name. \a argc is the number of parameters provided by the + event (DISPPARAMS.cArgs), and \a argv is the pointer to the + parameter values (DISPPARAMS.rgvarg). Note that the order of parameter + values is turned around, ie. the last element of the array is the first + parameter in the function. + + \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 20 + + Use this signal if the event has parameters of unsupported data + types. Otherwise, connect directly to the signal \a name. +*/ + +/*! + \fn void QAxBase::propertyChanged(const QString &name) + + If the COM object supports property notification, this signal gets + emitted when the property called \a name is changed. +*/ + +/*! + \fn void QAxBase::exception(int code, const QString &source, const QString &desc, const QString &help) + + This signal is emitted when the COM object throws an exception while called using the OLE automation + interface IDispatch. \a code, \a source, \a desc and \a help provide information about the exception as + provided by the COM server and can be used to provide useful feedback to the end user. \a help includes + the help file, and the help context ID in brackets, e.g. "filename [id]". +*/ + +/*! + \fn QObject *QAxBase::qObject() const + \internal +*/ + +/*! + \fn const char *QAxBase::className() const + \internal +*/ + +QT_END_NAMESPACE +#endif //QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/container/qaxbase.h b/src/activeqt/container/qaxbase.h new file mode 100644 index 0000000..ab1bc7f --- /dev/null +++ b/src/activeqt/container/qaxbase.h @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXBASE_H +#define QAXBASE_H + +#include <QtCore/qdatastream.h> +#include <QtCore/qmap.h> +#include <QtCore/qobject.h> +#include <QtCore/qvariant.h> + +struct IUnknown; +struct IDispatch; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +struct QUuid; +class QAxEventSink; +class QAxObject; +class QAxBasePrivate; +struct QAxMetaObject; + +class QAxBase +{ + QDOC_PROPERTY(QString control READ control WRITE setControl) + +public: + typedef QMap<QString, QVariant> PropertyBag; + + QAxBase(IUnknown *iface = 0); + virtual ~QAxBase(); + + QString control() const; + + long queryInterface(const QUuid &, void**) const; + + QVariant dynamicCall(const char *name, const QVariant &v1 = QVariant(), + const QVariant &v2 = QVariant(), + const QVariant &v3 = QVariant(), + const QVariant &v4 = QVariant(), + const QVariant &v5 = QVariant(), + const QVariant &v6 = QVariant(), + const QVariant &v7 = QVariant(), + const QVariant &v8 = QVariant()); + QVariant dynamicCall(const char *name, QList<QVariant> &vars); + QAxObject *querySubObject(const char *name, const QVariant &v1 = QVariant(), + const QVariant &v2 = QVariant(), + const QVariant &v3 = QVariant(), + const QVariant &v4 = QVariant(), + const QVariant &v5 = QVariant(), + const QVariant &v6 = QVariant(), + const QVariant &v7 = QVariant(), + const QVariant &v8 = QVariant()); + QAxObject* querySubObject(const char *name, QList<QVariant> &vars); + + virtual const QMetaObject *metaObject() const; + virtual int qt_metacall(QMetaObject::Call, int, void **); + + virtual QObject *qObject() const = 0; + virtual const char *className() const = 0; + + PropertyBag propertyBag() const; + void setPropertyBag(const PropertyBag&); + + QString generateDocumentation(); + + virtual bool propertyWritable(const char*) const; + virtual void setPropertyWritable(const char*, bool); + + bool isNull() const; + + QStringList verbs() const; + + QVariant asVariant() const; + +#ifdef qdoc +Q_SIGNALS: + void signal(const QString&,int,void*); + void propertyChanged(const QString&); + void exception(int,const QString&,const QString&,const QString&); +#endif + +public: + virtual void clear(); + bool setControl(const QString&); + + void disableMetaObject(); + void disableClassInfo(); + void disableEventSink(); + +protected: + virtual bool initialize(IUnknown** ptr); + bool initializeRemote(IUnknown** ptr); + bool initializeLicensed(IUnknown** ptr); + bool initializeActive(IUnknown** ptr); + bool initializeFromFile(IUnknown** ptr); + + void internalRelease(); + void initializeFrom(QAxBase *that); + void connectNotify(); + long indexOfVerb(const QString &verb) const; + +private: + friend class QAxEventSink; + friend void *qax_createObjectWrapper(int, IUnknown*); + bool initializeLicensedHelper(void *factory, const QString &key, IUnknown **ptr); + QAxBasePrivate *d; + QAxMetaObject *internalMetaObject() const; + + virtual const QMetaObject *parentMetaObject() const = 0; + int internalProperty(QMetaObject::Call, int index, void **v); + int internalInvoke(QMetaObject::Call, int index, void **v); + bool dynamicCallHelper(const char *name, void *out, QList<QVariant> &var, QByteArray &type); + + static QMetaObject staticMetaObject; +}; + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +template <> inline QAxBase *qobject_cast_helper<QAxBase*>(const QObject *o, QAxBase *) +#else +template <> inline QAxBase *qobject_cast<QAxBase*>(const QObject *o) +#endif +{ + void *result = o ? const_cast<QObject *>(o)->qt_metacast("QAxBase") : 0; + return (QAxBase*)(result); +} + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +template <> inline QAxBase *qobject_cast_helper<QAxBase*>(QObject *o, QAxBase *) +#else +template <> inline QAxBase *qobject_cast<QAxBase*>(QObject *o) +#endif +{ + void *result = o ? o->qt_metacast("QAxBase") : 0; + return (QAxBase*)(result); +} + +extern QString qax_generateDocumentation(QAxBase *); + +inline QString QAxBase::generateDocumentation() +{ + return qax_generateDocumentation(this); +} + +#ifndef QT_NO_DATASTREAM +inline QDataStream &operator >>(QDataStream &s, QAxBase &c) +{ + QAxBase::PropertyBag bag; + c.qObject()->blockSignals(true); + QString control; + s >> control; + c.setControl(control); + s >> bag; + c.setPropertyBag(bag); + c.qObject()->blockSignals(false); + + return s; +} + +inline QDataStream &operator <<(QDataStream &s, const QAxBase &c) +{ + QAxBase::PropertyBag bag = c.propertyBag(); + s << c.control(); + s << bag; + + return s; +} +#endif // QT_NO_DATASTREAM + +QT_END_NAMESPACE + +#ifndef Q_COM_METATYPE_DECLARED +#define Q_COM_METATYPE_DECLARED + +Q_DECLARE_METATYPE(IUnknown*) +Q_DECLARE_METATYPE(IDispatch*) + +#endif + +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXBASE_H diff --git a/src/activeqt/container/qaxdump.cpp b/src/activeqt/container/qaxdump.cpp new file mode 100644 index 0000000..e6de9de --- /dev/null +++ b/src/activeqt/container/qaxdump.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxbase.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qmetaobject.h> +#include <quuid.h> +#include <qt_windows.h> +#include <qtextstream.h> + +#include <ctype.h> + +#include "../shared/qaxtypes.h" + +QT_BEGIN_NAMESPACE + +QString qax_docuFromName(ITypeInfo *typeInfo, const QString &name) +{ + QString docu; + if (!typeInfo) + return docu; + + MEMBERID memId; + BSTR names = QStringToBSTR(name); + typeInfo->GetIDsOfNames((BSTR*)&names, 1, &memId); + SysFreeString(names); + if (memId != DISPID_UNKNOWN) { + BSTR docStringBstr, helpFileBstr; + ulong helpContext; + HRESULT hres = typeInfo->GetDocumentation(memId, 0, &docStringBstr, &helpContext, &helpFileBstr); + QString docString = QString::fromWCharArray(docStringBstr); + QString helpFile = QString::fromWCharArray(helpFileBstr); + SysFreeString(docStringBstr); + SysFreeString(helpFileBstr); + if (hres == S_OK) { + if (!docString.isEmpty()) + docu += docString + QLatin1String("\n"); + if (!helpFile.isEmpty()) + docu += QString::fromLatin1("For more information, see help context %1 in %2.").arg((uint)helpContext).arg(helpFile); + } + } + + return docu; +} + +static inline QString docuFromName(ITypeInfo *typeInfo, const QString &name) +{ + return QLatin1String("<p>") + qax_docuFromName(typeInfo, name) + QLatin1String("\n"); +} + +static QByteArray namedPrototype(const QList<QByteArray> ¶meterTypes, const QList<QByteArray> ¶meterNames, int numDefArgs = 0) +{ + QByteArray prototype("("); + for (int p = 0; p < parameterTypes.count(); ++p) { + QByteArray type(parameterTypes.at(p)); + prototype += type; + + if (p < parameterNames.count()) + prototype += ' ' + parameterNames.at(p); + + if (numDefArgs >= parameterTypes.count() - p) + prototype += " = 0"; + if (p < parameterTypes.count() - 1) + prototype += ", "; + } + prototype += ')'; + + return prototype; +} + +static QByteArray toType(const QByteArray &t) +{ + QByteArray type = t; + int vartype = QVariant::nameToType(type); + if (vartype == QVariant::Invalid) + type = "int"; + + if (type.at(0) == 'Q') + type = type.mid(1); + type[0] = toupper(type.at(0)); + if (type == "VariantList") + type = "List"; + else if (type == "Map<QVariant,QVariant>") + type = "Map"; + else if (type == "Uint") + type = "UInt"; + + return "to" + type + "()"; +} + +QString qax_generateDocumentation(QAxBase *that) +{ + that->metaObject(); + + if (that->isNull()) + return QString(); + + ITypeInfo *typeInfo = 0; + IDispatch *dispatch = 0; + that->queryInterface(IID_IDispatch, (void**)&dispatch); + if (dispatch) + dispatch->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &typeInfo); + + QString docu; + QTextStream stream(&docu, QIODevice::WriteOnly); + + const QMetaObject *mo = that->metaObject(); + QString coClass = QLatin1String(mo->classInfo(mo->indexOfClassInfo("CoClass")).value()); + + stream << "<h1 align=center>" << coClass << " Reference</h1>" << endl; + stream << "<p>The " << coClass << " COM object is a " << that->qObject()->metaObject()->className(); + stream << " with the CLSID " << that->control() << ".</p>" << endl; + + stream << "<h3>Interfaces</h3>" << endl; + stream << "<ul>" << endl; + const char *inter = 0; + int interCount = 1; + while ((inter = mo->classInfo(mo->indexOfClassInfo("Interface " + QByteArray::number(interCount))).value())) { + stream << "<li>" << inter << endl; + interCount++; + } + stream << "</ul>" << endl; + + stream << "<h3>Event Interfaces</h3>" << endl; + stream << "<ul>" << endl; + interCount = 1; + while ((inter = mo->classInfo(mo->indexOfClassInfo("Event Interface " + QByteArray::number(interCount))).value())) { + stream << "<li>" << inter << endl; + interCount++; + } + stream << "</ul>" << endl; + + QList<QString> methodDetails, propDetails; + + const int slotCount = mo->methodCount(); + if (slotCount) { + stream << "<h2>Public Slots:</h2>" << endl; + stream << "<ul>" << endl; + + int defArgCount = 0; + for (int islot = mo->methodOffset(); islot < slotCount; ++islot) { + const QMetaMethod slot = mo->method(islot); + if (slot.methodType() != QMetaMethod::Slot) + continue; + + if (slot.attributes() & QMetaMethod::Cloned) { + ++defArgCount; + continue; + } + + QByteArray returntype(slot.typeName()); + if (returntype.isEmpty()) + returntype = "void"; + QByteArray prototype = namedPrototype(slot.parameterTypes(), slot.parameterNames(), defArgCount); + QByteArray signature = slot.signature(); + QByteArray name = signature.left(signature.indexOf('(')); + stream << "<li>" << returntype << " <a href=\"#" << name << "\"><b>" << name << "</b></a>" << prototype << ";</li>" << endl; + + prototype = namedPrototype(slot.parameterTypes(), slot.parameterNames()); + QString detail = QString::fromLatin1("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>") + + QLatin1String(returntype.constData()) + QLatin1Char(' ') + + QLatin1String(name.constData()) + QLatin1Char(' ') + + QString::fromLatin1(prototype.constData()) + QLatin1String("<tt> [slot]</tt></h3>\n"); + prototype = namedPrototype(slot.parameterTypes(), QList<QByteArray>()); + detail += docuFromName(typeInfo, QString::fromLatin1(name.constData())); + detail += QLatin1String("<p>Connect a signal to this slot:<pre>\n"); + detail += QString::fromLatin1("\tQObject::connect(sender, SIGNAL(someSignal") + QString::fromLatin1(prototype.constData()) + + QLatin1String("), object, SLOT(") + QString::fromLatin1(name.constData()) + + QString::fromLatin1(prototype.constData()) + QLatin1String("));"); + detail += QLatin1String("</pre>\n"); + + if (1) { + detail += QLatin1String("<p>Or call the function directly:<pre>\n"); + + bool hasParams = slot.parameterTypes().count() != 0; + if (hasParams) + detail += QLatin1String("\tQVariantList params = ...\n"); + detail += QLatin1String("\t"); + QByteArray functionToCall = "dynamicCall"; + if (returntype == "IDispatch*" || returntype == "IUnknown*") { + functionToCall = "querySubObject"; + returntype = "QAxObject *"; + } + if (returntype != "void") + detail += QLatin1String(returntype.constData()) + QLatin1String(" result = "); + detail += QLatin1String("object->") + QLatin1String(functionToCall.constData()) + + QLatin1String("(\"" + name + prototype + '\"'); + if (hasParams) + detail += QLatin1String(", params"); + detail += QLatin1Char(')'); + if (returntype != "void" && returntype != "QAxObject *" && returntype != "QVariant") + detail += QLatin1Char('.') + QLatin1String(toType(returntype)); + detail += QLatin1String(";</pre>\n"); + } else { + detail += QLatin1String("<p>This function has parameters of unsupported types and cannot be called directly."); + } + + methodDetails << detail; + defArgCount = 0; + } + + stream << "</ul>" << endl; + } + int signalCount = mo->methodCount(); + if (signalCount) { + ITypeLib *typeLib = 0; + if (typeInfo) { + UINT index = 0; + typeInfo->GetContainingTypeLib(&typeLib, &index); + typeInfo->Release(); + } + typeInfo = 0; + + stream << "<h2>Signals:</h2>" << endl; + stream << "<ul>" << endl; + + for (int isignal = mo->methodOffset(); isignal < signalCount; ++isignal) { + const QMetaMethod signal(mo->method(isignal)); + if (signal.methodType() != QMetaMethod::Signal) + continue; + + QByteArray prototype = namedPrototype(signal.parameterTypes(), signal.parameterNames()); + QByteArray signature = signal.signature(); + QByteArray name = signature.left(signature.indexOf('(')); + stream << "<li>void <a href=\"#" << name << "\"><b>" << name << "</b></a>" << prototype << ";</li>" << endl; + + QString detail = QLatin1String("<h3><a name=") + QLatin1String(name.constData()) + QLatin1String("></a>void ") + + QLatin1String(name.constData()) + QLatin1Char(' ') + + QLatin1String(prototype.constData()) + QLatin1String("<tt> [signal]</tt></h3>\n"); + if (typeLib) { + interCount = 0; + do { + if (typeInfo) + typeInfo->Release(); + typeInfo = 0; + typeLib->GetTypeInfo(++interCount, &typeInfo); + QString typeLibDocu = docuFromName(typeInfo, QString::fromLatin1(name.constData())); + if (!typeLibDocu.isEmpty()) { + detail += typeLibDocu; + break; + } + } while (typeInfo); + } + prototype = namedPrototype(signal.parameterTypes(), QList<QByteArray>()); + detail += QLatin1String("<p>Connect a slot to this signal:<pre>\n"); + detail += QLatin1String("\tQObject::connect(object, SIGNAL(") + QString::fromLatin1(name.constData()) + + QString::fromLatin1(prototype.constData()) + + QLatin1String("), receiver, SLOT(someSlot") + QString::fromLatin1(prototype.constData()) + QLatin1String("));"); + detail += QLatin1String("</pre>\n"); + + methodDetails << detail; + if (typeInfo) + typeInfo->Release(); + typeInfo = 0; + } + stream << "</ul>" << endl; + + if (typeLib) + typeLib->Release(); + } + + const int propCount = mo->propertyCount(); + if (propCount) { + if (dispatch) + dispatch->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &typeInfo); + stream << "<h2>Properties:</h2>" << endl; + stream << "<ul>" << endl; + + for (int iprop = 0; iprop < propCount; ++iprop) { + const QMetaProperty prop = mo->property(iprop); + QByteArray name(prop.name()); + QByteArray type(prop.typeName()); + + stream << "<li>" << type << " <a href=\"#" << name << "\"><b>" << name << "</b></a>;</li>" << endl; + QString detail = QLatin1String("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>") + + QLatin1String(type.constData()) + + QLatin1Char(' ') + QLatin1String(name.constData()) + QLatin1String("</h3>\n"); + detail += docuFromName(typeInfo, QString::fromLatin1(name)); + QVariant::Type vartype = QVariant::nameToType(type); + if (!prop.isReadable()) + continue; + + if (prop.isEnumType()) + vartype = QVariant::Int; + + if (vartype != QVariant::Invalid) { + detail += QLatin1String("<p>Read this property's value using QObject::property:<pre>\n"); + if (prop.isEnumType()) + detail += QLatin1String("\tint val = "); + else + detail += QLatin1Char('\t') + QLatin1String(type.constData()) + QLatin1String(" val = "); + detail += QLatin1String("object->property(\"") + QLatin1String(name.constData()) + + QLatin1String("\").") + QLatin1String(toType(type).constData()) + QLatin1String(";\n"); + detail += QLatin1String("</pre>\n"); + } else if (type == "IDispatch*" || type == "IUnknown*") { + detail += QLatin1String("<p>Get the subobject using querySubObject:<pre>\n"); + detail += QLatin1String("\tQAxObject *") + QLatin1String(name.constData()) + + QLatin1String(" = object->querySubObject(\"") + QLatin1String(name.constData()) + QLatin1String("\");\n"); + detail += QLatin1String("</pre>\n"); + } else { + detail += QLatin1String("<p>This property is of an unsupported type.\n"); + } + if (prop.isWritable()) { + detail += QLatin1String("Set this property' value using QObject::setProperty:<pre>\n"); + if (prop.isEnumType()) { + detail += QLatin1String("\tint newValue = ... // string representation of values also supported\n"); + } else { + detail += QLatin1String("\t") + QString::fromLatin1(type.constData()) + QLatin1String(" newValue = ...\n"); + } + detail += QLatin1String("\tobject->setProperty(\"") + QString::fromLatin1(name) + QLatin1String("\", newValue);\n"); + detail += QLatin1String("</pre>\n"); + detail += QLatin1String("Or using the "); + QByteArray setterSlot; + if (isupper(name.at(0))) { + setterSlot = "Set" + name; + } else { + QByteArray nameUp = name; + nameUp[0] = toupper(nameUp.at(0)); + setterSlot = "set" + nameUp; + } + detail += QLatin1String("<a href=\"#") + QString::fromLatin1(setterSlot) + QLatin1String("\">") + + QString::fromLatin1(setterSlot.constData()) + QLatin1String("</a> slot.\n"); + } + if (prop.isEnumType()) { + detail += QLatin1String("<p>See also <a href=\"#") + QString::fromLatin1(type) + + QLatin1String("\">") + QString::fromLatin1(type) + QLatin1String("</a>.\n"); + } + + propDetails << detail; + } + stream << "</ul>" << endl; + } + + const int enumCount = mo->enumeratorCount(); + if (enumCount) { + stream << "<hr><h2>Member Type Documentation</h2>" << endl; + for (int i = 0; i < enumCount; ++i) { + const QMetaEnum enumdata = mo->enumerator(i); + stream << "<h3><a name=" << enumdata.name() << "></a>" << enumdata.name() << "</h3>" << endl; + stream << "<ul>" << endl; + for (int e = 0; e < enumdata.keyCount(); ++e) { + stream << "<li>" << enumdata.key(e) << "\t=" << enumdata.value(e) << "</li>" << endl; + } + stream << "</ul>" << endl; + } + } + if (methodDetails.count()) { + stream << "<hr><h2>Member Function Documentation</h2>" << endl; + for (int i = 0; i < methodDetails.count(); ++i) + stream << methodDetails.at(i) << endl; + } + if (propDetails.count()) { + stream << "<hr><h2>Property Documentation</h2>" << endl; + for (int i = 0; i < propDetails.count(); ++i) + stream << propDetails.at(i) << endl; + } + + if (typeInfo) + typeInfo->Release(); + if (dispatch) + dispatch->Release(); + return docu; +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/container/qaxobject.cpp b/src/activeqt/container/qaxobject.cpp new file mode 100644 index 0000000..26cd26a --- /dev/null +++ b/src/activeqt/container/qaxobject.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxobject.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <quuid.h> +#include <qmetaobject.h> +#include <qstringlist.h> + +#include <windows.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QAxObject + \brief The QAxObject class provides a QObject that wraps a COM object. + + \inmodule QAxContainer + + A QAxObject can be instantiated as an empty object, with the name + of the COM object it should wrap, or with a pointer to the + IUnknown that represents an existing COM object. If the COM object + implements the \c IDispatch interface, the properties, methods and + events of that object become available as Qt properties, slots and + signals. The base class, QAxBase, provides an API to access the + COM object directly through the IUnknown pointer. + + QAxObject is a QObject and can be used as such, e.g. it can be + organized in an object hierarchy, receive events and connect to + signals and slots. + + QAxObject also inherits most of its ActiveX-related functionality + from QAxBase, notably dynamicCall() and querySubObject(). + + \warning + You can subclass QAxObject, but you cannot use the Q_OBJECT macro + in the subclass (the generated moc-file will not compile), so you + cannot add further signals, slots or properties. This limitation is + due to the metaobject information generated in runtime. + To work around this problem, aggregate the QAxObject as a member of + the QObject subclass. + + \sa QAxBase, QAxWidget, QAxScript, {ActiveQt Framework} +*/ + +/*! + Creates an empty COM object and propagates \a parent to the + QObject constructor. To initialize the object, call \link + QAxBase::setControl() setControl \endlink. +*/ +QAxObject::QAxObject(QObject *parent) +: QObject(parent) +{ +} + +/*! + Creates a QAxObject that wraps the COM object \a c. \a parent is + propagated to the QObject constructor. + + \sa setControl() +*/ +QAxObject::QAxObject(const QString &c, QObject *parent) +: QObject(parent) +{ + setControl(c); +} + +/*! + Creates a QAxObject that wraps the COM object referenced by \a + iface. \a parent is propagated to the QObject constructor. +*/ +QAxObject::QAxObject(IUnknown *iface, QObject *parent) +: QObject(parent), QAxBase(iface) +{ +} + +/*! + Releases the COM object and destroys the QAxObject, + cleaning up all allocated resources. +*/ +QAxObject::~QAxObject() +{ + clear(); +} + +/*! + \internal +*/ +const QMetaObject *QAxObject::metaObject() const +{ + return QAxBase::metaObject(); +} + +/*! + \internal +*/ +const QMetaObject *QAxObject::parentMetaObject() const +{ + return &QObject::staticMetaObject; +} + +/*! + \internal +*/ +void *QAxObject::qt_metacast(const char *cname) +{ + if (!qstrcmp(cname, "QAxObject")) return (void*)this; + if (!qstrcmp(cname, "QAxBase")) return (QAxBase*)this; + return QObject::qt_metacast(cname); +} + +/*! + \internal +*/ +const char *QAxObject::className() const +{ + return "QAxObject"; +} + +/*! + \internal +*/ +int QAxObject::qt_metacall(QMetaObject::Call call, int id, void **v) +{ + id = QObject::qt_metacall(call, id, v); + if (id < 0) + return id; + return QAxBase::qt_metacall(call, id, v); +} + +/*! + \fn QObject *QAxObject::qObject() const + \internal +*/ + +/*! + \reimp +*/ +void QAxObject::connectNotify(const char *) +{ + QAxBase::connectNotify(); +} + +/*! + \since 4.1 + + Requests the COM object to perform the action \a verb. The + possible verbs are returned by verbs(). + + The function returns true if the object could perform the action, otherwise returns false. +*/ +bool QAxObject::doVerb(const QString &verb) +{ + if (!verbs().contains(verb)) + return false; + IOleObject *ole = 0; + queryInterface(IID_IOleObject, (void**)&ole); + if (!ole) + return false; + + LONG index = indexOfVerb(verb); + + HRESULT hres = ole->DoVerb(index, 0, 0, 0, 0, 0); + + ole->Release(); + + return hres == S_OK; +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/container/qaxobject.h b/src/activeqt/container/qaxobject.h new file mode 100644 index 0000000..130814e --- /dev/null +++ b/src/activeqt/container/qaxobject.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXOBJECT_H +#define QAXOBJECT_H + +#include <ActiveQt/qaxbase.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +class QAxObject : public QObject, public QAxBase +{ + friend class QAxEventSink; +public: + const QMetaObject *metaObject() const; + void* qt_metacast(const char*); + int qt_metacall(QMetaObject::Call, int, void **); + QObject* qObject() const { return (QObject*)this; } + const char *className() const; + + QAxObject(QObject *parent = 0); + QAxObject(const QString &c, QObject *parent = 0); + QAxObject(IUnknown *iface, QObject *parent = 0); + ~QAxObject(); + + bool doVerb(const QString &verb); + +protected: + void connectNotify(const char *signal); + +private: + const QMetaObject *parentMetaObject() const; + static QMetaObject staticMetaObject; +}; + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +template <> inline QAxObject *qobject_cast_helper<QAxObject*>(const QObject *o, QAxObject *) +#else +template <> inline QAxObject *qobject_cast<QAxObject*>(const QObject *o) +#endif +{ + void *result = o ? const_cast<QObject *>(o)->qt_metacast("QAxObject") : 0; + return (QAxObject*)(result); +} + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +template <> inline QAxObject *qobject_cast_helper<QAxObject*>(QObject *o, QAxObject *) +#else +template <> inline QAxObject *qobject_cast<QAxObject*>(QObject *o) +#endif +{ + void *result = o ? o->qt_metacast("QAxObject") : 0; + return (QAxObject*)(result); +} + +QT_END_NAMESPACE +Q_DECLARE_METATYPE(QAxObject*) + +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXOBJECT_H diff --git a/src/activeqt/container/qaxscript.cpp b/src/activeqt/container/qaxscript.cpp new file mode 100644 index 0000000..7e038a5 --- /dev/null +++ b/src/activeqt/container/qaxscript.cpp @@ -0,0 +1,1290 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxscript.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#if defined(Q_CC_GNU) +# define QT_NO_QAXSCRIPT +#elif defined(Q_CC_BOR) && __BORLANDC__ < 0x560 +# define QT_NO_QAXSCRIPT +#endif + +#include <qapplication.h> +#include <qfile.h> +#include <qhash.h> +#include <qmetaobject.h> +#include <quuid.h> +#include <qwidget.h> + +#include <qt_windows.h> +#ifndef QT_NO_QAXSCRIPT +#include <initguid.h> +#include <activscp.h> +#endif + +#include "../shared/qaxtypes.h" + +QT_BEGIN_NAMESPACE + +struct QAxEngineDescriptor { QString name, extension, code; }; +static QList<QAxEngineDescriptor> engines; + +class QAxScriptManagerPrivate +{ +public: + QHash<QString, QAxScript*> scriptDict; + QHash<QString, QAxBase*> objectDict; +}; + +/* + \class QAxScriptSite + \brief The QAxScriptSite class implements a Windows Scripting Host + \internal + + The QAxScriptSite is used internally to communicate callbacks from the script + engine to the script manager. +*/ + +#ifndef QT_NO_QAXSCRIPT + +class QAxScriptSite : public IActiveScriptSite, public IActiveScriptSiteWindow +{ +public: + QAxScriptSite(QAxScript *script); + + ULONG WINAPI AddRef(); + ULONG WINAPI Release(); + HRESULT WINAPI QueryInterface(REFIID iid, void **ppvObject); + + HRESULT WINAPI GetLCID(LCID *plcid); + HRESULT WINAPI GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti); + HRESULT WINAPI GetDocVersionString(BSTR *pbstrVersion); + + HRESULT WINAPI OnScriptTerminate(const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo); + HRESULT WINAPI OnStateChange(SCRIPTSTATE ssScriptState); + HRESULT WINAPI OnScriptError(IActiveScriptError *pscripterror); + HRESULT WINAPI OnEnterScript(); + HRESULT WINAPI OnLeaveScript(); + + HRESULT WINAPI GetWindow(HWND *phwnd); + HRESULT WINAPI EnableModeless(BOOL fEnable); + +protected: + QWidget *window() const; + +private: + QAxScript *script; + unsigned long ref; +}; + +/* + Constructs the site for the \a s. +*/ +QAxScriptSite::QAxScriptSite(QAxScript *s) +: script(s), ref(1) +{ +} + +/* + Implements IUnknown::AddRef +*/ +ULONG WINAPI QAxScriptSite::AddRef() +{ + return ++ref; +} + +/* + Implements IUnknown::Release +*/ +ULONG WINAPI QAxScriptSite::Release() +{ + if (!--ref) { + delete this; + return 0; + } + return ref; +} + +/* + Implements IUnknown::QueryInterface +*/ +HRESULT WINAPI QAxScriptSite::QueryInterface(REFIID iid, void **ppvObject) +{ + *ppvObject = 0; + if (iid == IID_IUnknown) + *ppvObject = (IUnknown*)(IActiveScriptSite*)this; + else if (iid == IID_IActiveScriptSite) + *ppvObject = (IActiveScriptSite*)this; + else if (iid == IID_IActiveScriptSiteWindow) + *ppvObject = (IActiveScriptSiteWindow*)this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +/* + Implements IActiveScriptSite::GetLCID + + This method is not implemented. Use the system-defined locale. +*/ +HRESULT WINAPI QAxScriptSite::GetLCID(LCID * /*plcid*/) +{ + return E_NOTIMPL; +} + +/* + Implements IActiveScriptSite::GetItemInfo + + Tries to find the QAxBase for \a pstrName and returns the + relevant interfaces in \a item and \a type as requested through \a mask. +*/ +HRESULT WINAPI QAxScriptSite::GetItemInfo(LPCOLESTR pstrName, DWORD mask, IUnknown **item, ITypeInfo **type) +{ + if (item) + *item = 0; + else if (mask & SCRIPTINFO_IUNKNOWN) + return E_POINTER; + + if (type) + *type = 0; + else if (mask & SCRIPTINFO_ITYPEINFO) + return E_POINTER; + + QAxBase *object = script->findObject(QString::fromWCharArray(pstrName)); + if (!object) + return TYPE_E_ELEMENTNOTFOUND; + + if (mask & SCRIPTINFO_IUNKNOWN) + object->queryInterface(IID_IUnknown, (void**)item); + if (mask & SCRIPTINFO_ITYPEINFO) { + IProvideClassInfo *classInfo = 0; + object->queryInterface(IID_IProvideClassInfo, (void**)&classInfo); + if (classInfo) { + classInfo->GetClassInfo(type); + classInfo->Release(); + } + } + return S_OK; +} + +/* + Implements IActiveScriptSite::GetDocVersionString + + This method is not implemented. The scripting engine should assume + that the script is in sync with the document. +*/ +HRESULT WINAPI QAxScriptSite::GetDocVersionString(BSTR * /*version*/) +{ + return E_NOTIMPL; +} + +/* + Implements IActiveScriptSite::OnScriptTerminate + + This method is usually not called, but if it is it fires + QAxScript::finished(). +*/ +HRESULT WINAPI QAxScriptSite::OnScriptTerminate(const VARIANT *result, const EXCEPINFO *exception) +{ + emit script->finished(); + + if (result && result->vt != VT_EMPTY) + emit script->finished(VARIANTToQVariant(*result, 0)); + if (exception) + emit script->finished(exception->wCode, + QString::fromWCharArray(exception->bstrSource), + QString::fromWCharArray(exception->bstrDescription), + QString::fromWCharArray(exception->bstrHelpFile) + ); + return S_OK; +} + +/* + Implements IActiveScriptSite::OnEnterScript + + Fires QAxScript::entered() to inform the host that the + scripting engine has begun executing the script code. +*/ +HRESULT WINAPI QAxScriptSite::OnEnterScript() +{ + emit script->entered(); + return S_OK; +} + +/* + Implements IActiveScriptSite::OnLeaveScript + + Fires QAxScript::finished() to inform the host that the + scripting engine has returned from executing the script code. +*/ +HRESULT WINAPI QAxScriptSite::OnLeaveScript() +{ + emit script->finished(); + return S_OK; +} + +/* + Implements IActiveScriptSite::OnScriptError + + Fires QAxScript::error() to inform the host that an + that an execution error occurred while the engine was running the script. +*/ +HRESULT WINAPI QAxScriptSite::OnScriptError(IActiveScriptError *error) +{ + EXCEPINFO exception; + memset(&exception, 0, sizeof(exception)); + DWORD context; + ULONG lineNumber; + LONG charPos; + BSTR bstrLineText; + QString lineText; + + error->GetExceptionInfo(&exception); + error->GetSourcePosition(&context, &lineNumber, &charPos); + HRESULT hres = error->GetSourceLineText(&bstrLineText); + if (hres == S_OK) { + lineText = QString::fromWCharArray(bstrLineText); + SysFreeString(bstrLineText); + } + SysFreeString(exception.bstrSource); + SysFreeString(exception.bstrDescription); + SysFreeString(exception.bstrHelpFile); + + emit script->error(exception.wCode, QString::fromWCharArray(exception.bstrDescription), lineNumber, lineText); + + return S_OK; +} + +/* + Implements IActiveScriptSite::OnStateChange + + Fires QAxScript::stateChanged() to inform the + the host that the scripting engine has changed states. +*/ +HRESULT WINAPI QAxScriptSite::OnStateChange(SCRIPTSTATE ssScriptState) +{ + emit script->stateChanged(ssScriptState); + return S_OK; +} + +/* + \internal + Returns the toplevel widget parent of this script, or + the application' active window if there is no widget parent. +*/ +QWidget *QAxScriptSite::window() const +{ + QWidget *w = 0; + QObject *p = script->parent(); + while (!w && p) { + w = qobject_cast<QWidget*>(p); + p = p->parent(); + } + + if (w) + w = w->window(); + if (!w && qApp) + w = qApp->activeWindow(); + + return w; +} + +/* + Implements IActiveScriptSiteWindow::GetWindow + + Retrieves the handle to a window that can act as the owner of a + pop-up window that the scripting engine must display. +*/ +HRESULT WINAPI QAxScriptSite::GetWindow(HWND *phwnd) +{ + if (!phwnd) + return E_POINTER; + + *phwnd = 0; + QWidget *w = window(); + if (!w) + return E_FAIL; + + *phwnd = w->winId(); + return S_OK; +} + +/* + Implements IActiveScriptSiteWindow::EnableModeless + + Causes the host to enable or disable its main window + as well as any modeless dialog boxes. +*/ +HRESULT WINAPI QAxScriptSite::EnableModeless(BOOL fEnable) +{ + QWidget *w = window(); + if (!w) + return E_FAIL; + + EnableWindow(w->winId(), fEnable); + return S_OK; +} + +#endif //QT_NO_QAXSCRIPT + + +/*! + \class QAxScriptEngine + \brief The QAxScriptEngine class provides a wrapper around a script engine. + \inmodule QAxContainer + + Every instance of the QAxScriptEngine class represents an interpreter + for script code in a particular scripting language. The class is usually + not used directly. The QAxScript and QAxScriptManager classes provide + convenient functions to handle and call script code. + + Direct access to the script engine is provided through + queryInterface(). + + \warning This class is not available with the bcc5.5 and MingW + compilers. + + \sa QAxScript, QAxScriptManager, QAxBase, {ActiveQt Framework} +*/ + +/*! + \enum QAxScriptEngine::State + + The State enumeration defines the different states a script + engine can be in. + + \value Uninitialized The script has been created, but not yet initialized + \value Initialized The script has been initialized, but is not running + \value Started The script can execute code, but does not yet handle events + \value Connected The script can execute code and is connected so + that it can handle events + \value Disconnected The script is loaded, but is not connected to + event sources + \value Closed The script has been closed. +*/ + +/*! + Constructs a QAxScriptEngine object interpreting script code in \a language + provided by the code in \a script. This is usually done by the QAxScript + class when \link QAxScript::load() loading a script\endlink. + + Instances of QAxScriptEngine should always have both a language and a + script. +*/ +QAxScriptEngine::QAxScriptEngine(const QString &language, QAxScript *script) +: QAxObject(script), script_code(script), engine(0), script_language(language) +{ +#ifdef QT_CHECK_STATE + if (language.isEmpty()) + qWarning("QAxScriptEngine: created without language"); + + if (!script_code) + qWarning("QAxScriptEngine: created without script"); +#endif + setObjectName(QLatin1String("QAxScriptEngine_") + language); + disableClassInfo(); + disableEventSink(); +} + +/*! + Destroys the QAxScriptEngine object, releasing all allocated + resources. +*/ +QAxScriptEngine::~QAxScriptEngine() +{ +#ifndef QT_NO_QAXSCRIPT + if (engine) { + engine->SetScriptState(SCRIPTSTATE_DISCONNECTED); + engine->Close(); + engine->Release(); + } +#endif +} + +/*! + \fn QString QAxScriptEngine::scriptLanguage() const + Returns the scripting language, for example "VBScript", + or "JScript". +*/ + +/*! + \reimp +*/ +bool QAxScriptEngine::initialize(IUnknown **ptr) +{ + *ptr = 0; + +#ifndef QT_NO_QAXSCRIPT + if (!script_code || script_language.isEmpty()) + return false; + + CLSID clsid; + HRESULT hres = CLSIDFromProgID((wchar_t*)script_language.utf16(), &clsid); + if(FAILED(hres)) + return false; + + CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void**)&engine); + if (!engine) + return false; + + IActiveScriptParse *parser = 0; + engine->QueryInterface(IID_IActiveScriptParse, (void**)&parser); + if (!parser) { + engine->Release(); + engine = 0; + return false; + } + + if (engine->SetScriptSite(script_code->script_site) != S_OK) { + engine->Release(); + engine = 0; + return false; + } + if (parser->InitNew() != S_OK) { + parser->Release(); + engine->Release(); + engine = 0; + return false; + } + + BSTR bstrCode = QStringToBSTR(script_code->scriptCode()); +#ifdef Q_OS_WIN64 + hres = parser->ParseScriptText(bstrCode, 0, 0, 0, DWORDLONG(this), 0, SCRIPTTEXT_ISVISIBLE, 0, 0); +#else + hres = parser->ParseScriptText(bstrCode, 0, 0, 0, DWORD(this), 0, SCRIPTTEXT_ISVISIBLE, 0, 0); +#endif + SysFreeString(bstrCode); + + parser->Release(); + parser = 0; + + script_code->updateObjects(); + + if (engine->SetScriptState(SCRIPTSTATE_CONNECTED) != S_OK) { + engine = 0; + return false; + } + + IDispatch *scriptDispatch = 0; + engine->GetScriptDispatch(0, &scriptDispatch); + if (scriptDispatch) { + scriptDispatch->QueryInterface(IID_IUnknown, (void**)ptr); + scriptDispatch->Release(); + } +#endif + + return *ptr != 0; +} + +/*! + \fn bool QAxScriptEngine::isValid() const + + Returns true if the script engine has been initialized + correctly; otherwise returns false. +*/ + +/*! + Returns true if the script engine supports introspection; + otherwise returns false. +*/ +bool QAxScriptEngine::hasIntrospection() const +{ + if (!isValid()) + return false; + + IDispatch *scriptDispatch = 0; + QAxBase::queryInterface(IID_IDispatch, (void**)&scriptDispatch); + if (!scriptDispatch) + return false; + + UINT tic = 0; + HRESULT hres = scriptDispatch->GetTypeInfoCount(&tic); + scriptDispatch->Release(); + return hres == S_OK && tic > 0; +} + +/*! + Requests the interface \a uuid from the script engine object and + sets the value of \a iface to the provided interface, or to 0 if + the requested interface could not be provided. + + Returns the result of the QueryInterface implementation of the COM + object. +*/ +long QAxScriptEngine::queryInterface(const QUuid &uuid, void **iface) const +{ + *iface = 0; + if (!engine) + return E_NOTIMPL; + +#ifndef QT_NO_QAXSCRIPT + return engine->QueryInterface(uuid, iface); +#else + return E_NOTIMPL; +#endif +} + +/*! + Returns the state of the script engine. +*/ +QAxScriptEngine::State QAxScriptEngine::state() const +{ + if (!engine) + return Uninitialized; + +#ifndef QT_NO_QAXSCRIPT + SCRIPTSTATE state; + engine->GetScriptState(&state); + return (State)state; +#else + return Uninitialized; +#endif +} + +/*! + Sets the state of the script engine to \a st. + Calling this function is usually not necessary. +*/ +void QAxScriptEngine::setState(State st) +{ +#ifndef QT_NO_QAXSCRIPT + if (!engine) + return; + + engine->SetScriptState((SCRIPTSTATE)st); +#endif +} + +/*! + Registers an item with the script engine. Script code can + refer to this item using \a name. +*/ +void QAxScriptEngine::addItem(const QString &name) +{ +#ifndef QT_NO_QAXSCRIPT + if (!engine) + return; + + engine->AddNamedItem((wchar_t*)name.utf16(), SCRIPTITEM_ISSOURCE|SCRIPTITEM_ISVISIBLE); +#endif +} + +/*! + \class QAxScript + \brief The QAxScript class provides a wrapper around script code. + \inmodule QAxContainer + + Every instance of the QAxScript class represents a piece of + scripting code in a particular scripting language. The code is + loaded into the script engine using load(). Functions declared + in the code can be called using call(). + + The script provides scriptEngine() provides feedback to the + application through signals. The most important signal is the + error() signal. Direct access to the QAxScriptEngine is provided + through the scriptEngine() function. + + \warning This class is not available with the bcc5.5 and MingW + compilers. + + \sa QAxScriptEngine, QAxScriptManager, QAxBase, {ActiveQt Framework} +*/ + +/*! + \enum QAxScript::FunctionFlags + + This FunctionFlags enum describes formatting for function introspection. + + \value FunctionNames Only function names are returned. + \value FunctionSignatures Returns the functions with signatures. +*/ + +/*! + Constructs a QAxScript object called \a name and registers + it with the QAxScriptManager \a manager. This is usually done by the + QAxScriptManager class when \link QAxScriptManager::load() loading a + script\endlink. + + A script should always have a name. A manager is necessary to allow + the script code to reference objects in the application. The \a manager + takes ownership of the object. +*/ +QAxScript::QAxScript(const QString &name, QAxScriptManager *manager) +: QObject(manager), script_name(name), script_manager(manager), +script_engine(0) +{ + if (manager) { + manager->d->scriptDict.insert(name, this); + connect(this, SIGNAL(error(int,QString,int,QString)), + manager, SLOT(scriptError(int,QString,int,QString))); + } + +#ifndef QT_NO_QAXSCRIPT + script_site = new QAxScriptSite(this); +#else + script_site = 0; +#endif +} + +/*! + Destroys the object, releasing all allocated resources. +*/ +QAxScript::~QAxScript() +{ + delete script_engine; + script_engine = 0; + +#ifndef QT_NO_QAXSCRIPT + script_site->Release(); +#endif +} + +/*! + Loads the script source \a code written in language \a language + into the script engine. Returns true if \a code was successfully + entered into the script engine; otherwise returns false. + + If \a language is empty (the default) it will be determined + heuristically. If \a code contains the string \c {End Sub} it will + be interpreted as VBScript, otherwise as JScript. Additional + scripting languages can be registered using + QAxScript::registerEngine(). + + This function can only be called once for each QAxScript object, + which is done automatically when using QAxScriptManager::load(). +*/ +bool QAxScript::load(const QString &code, const QString &language) +{ + if (script_engine || code.isEmpty()) + return false; + + script_code = code; + QString lang = language; + if (lang.isEmpty()) { + if (code.contains(QLatin1String("End Sub"), Qt::CaseInsensitive)) + lang = QLatin1String("VBScript"); + + QList<QAxEngineDescriptor>::ConstIterator it; + for (it = engines.begin(); it != engines.end(); ++it) { + QAxEngineDescriptor engine = *it; + if (engine.code.isEmpty()) + continue; + + if (code.contains(engine.code)) { + lang = engine.name; + break; + } + } + } + if (lang.isEmpty()) + lang = QLatin1String("JScript"); + + script_engine = new QAxScriptEngine(lang, this); + // trigger call to initialize + script_engine->metaObject(); + + return script_engine->isValid(); +} + +/*! + Returns a list of all the functions in this script if the respective + script engine supports introspection; otherwise returns an empty list. + The functions are either provided with full prototypes or only as + names, depending on the value of \a flags. + + \sa QAxScriptEngine::hasIntrospection() +*/ +QStringList QAxScript::functions(FunctionFlags flags) const +{ + QStringList functions; + + const QMetaObject *mo = script_engine->metaObject(); + for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) { + const QMetaMethod slot(mo->method(i)); + if (slot.methodType() != QMetaMethod::Slot || slot.access() != QMetaMethod::Public) + continue; + QString slotname = QString::fromLatin1(slot.signature()); + if (slotname.contains(QLatin1Char('_'))) + continue; + + if (flags == FunctionSignatures) + functions << slotname; + else + functions << slotname.left(slotname.indexOf(QLatin1Char('('))); + } + + return functions; +} + +/*! + Calls \a function, passing the parameters \a var1, \a var1, + \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8 + as arguments and returns the value returned by the function, or an + invalid QVariant if the function does not return a value or when + the function call failed. + + See QAxScriptManager::call() for more information about how to call + script functions. +*/ +QVariant QAxScript::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) +{ + if (!script_engine) + return QVariant(); + + return script_engine->dynamicCall(function.toLatin1(), var1, var2, var3, var4, var5, var6, var7, var8); +} + +/*! + \overload + + Calls \a function passing \a arguments as parameters, and returns + the result. Returns when the script's execution has finished. + + See QAxScriptManager::call() for more information about how to call + script functions. +*/ +QVariant QAxScript::call(const QString &function, QList<QVariant> &arguments) +{ + if (!script_engine) + return QVariant(); + + return script_engine->dynamicCall(function.toLatin1(), arguments); +} + +/*! \internal + Registers all objects in the manager with the script engine. +*/ +void QAxScript::updateObjects() +{ + if (!script_manager) + return; + + script_manager->updateScript(this); +} + +/*! \internal + Returns the object \a name registered with the manager. +*/ +QAxBase *QAxScript::findObject(const QString &name) +{ + if (!script_manager) + return 0; + + return script_manager->d->objectDict.value(name); +} + +/*! \fn QString QAxScript::scriptName() const + Returns the name of the script. +*/ + +/*! \fn QString QAxScript::scriptCode() const + Returns the script's code, or the null-string if no + code has been loaded yet. + + \sa load() +*/ + +/*! \fn QAxScriptEngine* QAxScript::scriptEngine() const + Returns a pointer to the script engine. + + You can use the object returned to connect signals to the + script functions, or to access the script engine directly. +*/ + +/*! \fn void QAxScript::entered() + + This signal is emitted when a script engine has started executing code. +*/ + +/*! \fn void QAxScript::finished() + + This signal is emitted when a script engine has finished executing code. +*/ + +/*! + \fn void QAxScript::finished(const QVariant &result) + \overload + + \a result contains the script's result. This will be an invalid + QVariant if the script has no return value. +*/ + +/*! \fn void QAxScript::finished(int code, const QString &source, + const QString &description, const QString &help) + \overload + + \a code, \a source, \a description and \a help contain exception information + when the script terminated. +*/ + +/*! \fn void QAxScript::stateChanged(int state); + + This signal is emitted when a script engine changes state. + \a state can be any value in the QAxScriptEngineState enumeration. +*/ + +/*! + \fn void QAxScript::error(int code, const QString &description, + int sourcePosition, const QString &sourceText) + + This signal is emitted when an execution error occurred while + running a script. + + \a code, \a description, \a sourcePosition and \a sourceText + contain information about the execution error. +*/ + + + +/*! + \class QAxScriptManager + \brief The QAxScriptManager class provides a bridge between application objects + and script code. + \inmodule QAxContainer + + The QAxScriptManager acts as a bridge between the COM objects embedded + in the Qt application through QAxObject or QAxWidget, and the scripting + languages available through the Windows Script technologies, usually JScript + and VBScript. + + Create one QAxScriptManager for each separate document in your + application, and add the COM objects the scripts need to access + using addObject(). Then load() the script sources and invoke the + functions using call(). + + \warning This class is not available with the bcc5.5 and MingW + compilers. + + \sa QAxScript, QAxScriptEngine, QAxBase, {ActiveQt Framework} +*/ + +/*! + Creates a QAxScriptManager object. \a parent is passed on to the + QObject constructor. + + It is usual to create one QAxScriptManager for each document in an + application. +*/ +QAxScriptManager::QAxScriptManager(QObject *parent) +: QObject(parent) +{ + d = new QAxScriptManagerPrivate; +} + +/*! + Destroys the objects, releasing all allocated resources. +*/ +QAxScriptManager::~QAxScriptManager() +{ + delete d; +} + +/*! + Returns a list with all the functions that are available. + Functions provided by script engines that don't support + introspection are not included in the list. + The functions are either provided with full prototypes or + only as names, depending on the value of \a flags. +*/ +QStringList QAxScriptManager::functions(QAxScript::FunctionFlags flags) const +{ + QStringList functions; + + QHash<QString, QAxScript*>::ConstIterator scriptIt; + for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) { + QAxScript *script = scriptIt.value(); + functions += script->functions(flags); + } + + return functions; +} + +/*! + Returns a list with the names of all the scripts. +*/ +QStringList QAxScriptManager::scriptNames() const +{ + QStringList scripts; + + QHash<QString, QAxScript*>::ConstIterator scriptIt; + for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) { + scripts << scriptIt.key(); + } + + return scripts; +} + +/*! + Returns the script called \a name. + + You can use the returned pointer to call functions directly + through QAxScript::call(), to access the script engine directly, or + to delete and thus unload the script. +*/ +QAxScript *QAxScriptManager::script(const QString &name) const +{ + return d->scriptDict.value(name); +} + +/*! + Adds \a object to the manager. Scripts handled by this manager + can access the object in the code using the object's + \l{QObject::objectName}{objectName} property. + + You must add all the necessary objects before loading any scripts. +*/ +void QAxScriptManager::addObject(QAxBase *object) +{ + QObject *obj = object->qObject(); + QString name = obj->objectName(); + if (d->objectDict.contains(name)) + return; + + d->objectDict.insert(name, object); + connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); +} + +/*! \fn void QAxScriptManager::addObject(QObject *object) + \overload + + Adds a generic COM wrapper for \a object to the manager. \a object + must be exposed as a COM object using the functionality provided + by the QAxServer module. Applications + using this function you must link against the qaxserver library. +*/ + +/*! + Loads the script source \a code using the script engine for \a + language. The script can later be referred to using its \a name + which should not be empty. + + The function returns a pointer to the script for the given + \a code if the \a code was loaded successfully; otherwise it + returns 0. + + If \a language is empty it will be determined heuristically. If \a + code contains the string "End Sub" it will be interpreted as + VBScript, otherwise as JScript. Additional script engines can be + registered using registerEngine(). + + You must add all the objects necessary (using addObject()) \e + before loading any scripts. If \a code declares a function that is + already available (no matter in which language) the first function + is overloaded and can no longer be called via call(); but it will + still be available by calling its \link script() script \endlink + directly. + + \sa addObject(), scriptNames(), functions() +*/ +QAxScript *QAxScriptManager::load(const QString &code, const QString &name, const QString &language) +{ + QAxScript *script = new QAxScript(name, this); + if (script->load(code, language)) + return script; + + delete script; + return 0; +} + +/*! + \overload + + Loads the source code from the \a file. The script can later be + referred to using its \a name which should not be empty. + + The function returns a pointer to the script engine for the code + in \a file if \a file was loaded successfully; otherwise it + returns 0. + + The script engine used is determined from the file's extension. By + default ".js" files are interpreted as JScript files, and ".vbs" + and ".dsm" files are interpreted as VBScript. Additional script + engines can be registered using registerEngine(). +*/ +QAxScript *QAxScriptManager::load(const QString &file, const QString &name) +{ + QFile f(file); + if (!f.open(QIODevice::ReadOnly)) + return 0; + QByteArray data = f.readAll(); + QString contents = QString::fromLocal8Bit(data, data.size()); + f.close(); + + if (contents.isEmpty()) + return 0; + + QString language; + if (file.endsWith(QLatin1String(".js"))) { + language = QLatin1String("JScript"); + } else { + QList<QAxEngineDescriptor>::ConstIterator it; + for (it = engines.begin(); it != engines.end(); ++it) { + QAxEngineDescriptor engine = *it; + if (engine.extension.isEmpty()) + continue; + + if (file.endsWith(engine.extension)) { + language = engine.name; + break; + } + } + } + + if (language.isEmpty()) + language = QLatin1String("VBScript"); + + QAxScript *script = new QAxScript(name, this); + if (script->load(contents, language)) + return script; + + delete script; + return 0; +} + +/*! + Calls \a function, passing the parameters \a var1, \a var1, + \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8 + as arguments and returns the value returned by the function, or an + invalid QVariant if the function does not return a value or when + the function call failed. The call returns when the script's + execution has finished. + + In most script engines the only supported parameter type is "const + QVariant&", for example, to call a JavaScript function + \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 0 + use + \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 1 + As with \link QAxBase::dynamicCall() dynamicCall \endlink the + parameters can directly be embedded in the function string. + \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 2 + However, this is slower. + + Functions provided by script engines that don't support + introspection are not available and must be called directly + using QAxScript::call() on the respective \link script() + script \endlink object. + + Note that calling this function can be significantely slower than + using call() on the respective QAxScript directly. +*/ +QVariant QAxScriptManager::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) +{ + QAxScript *s = script(function); + if (!s) { +#ifdef QT_CHECK_STATE + qWarning("QAxScriptManager::call: No script provides function %s, or this function\n" + "\tis provided through an engine that does not support introspection", function.latin1()); +#endif + return QVariant(); + } + + return s->call(function, var1, var2, var3, var4, var5, var6, var7, var8); +} + +/*! \overload + + Calls \a function passing \a arguments as parameters, and returns + the result. Returns when the script's execution has finished. +*/ +QVariant QAxScriptManager::call(const QString &function, QList<QVariant> &arguments) +{ + QAxScript *s = script(function); + if (!s) { +#ifdef QT_CHECK_STATE + qWarning("QAxScriptManager::call: No script provides function %s, or this function\n" + "\tis provided through an engine that does not support introspection", function.latin1()); +#endif + return QVariant(); + } + + QList<QVariant> args(arguments); + return s->call(function, args); +} + +/*! + Registers the script engine called \a name and returns true if the + engine was found; otherwise does nothing and returns false. + + The script engine will be used when loading files with the given + \a extension, or when loading source code that contains the string + \a code. +*/ +bool QAxScriptManager::registerEngine(const QString &name, const QString &extension, const QString &code) +{ + if (name.isEmpty()) + return false; + + CLSID clsid; + HRESULT hres = CLSIDFromProgID((wchar_t*)name.utf16(), &clsid); + if (hres != S_OK) + return false; + + QAxEngineDescriptor engine; + engine.name = name; + engine.extension = extension; + engine.code = code; + + engines.prepend(engine); + return true; +} + +/*! + Returns a file filter listing all the supported script languages. + This filter string is convenient for use with QFileDialog. +*/ +QString QAxScriptManager::scriptFileFilter() +{ + QString allFiles = QLatin1String("Script Files (*.js *.vbs *.dsm"); + QString specialFiles = QLatin1String(";;VBScript Files (*.vbs *.dsm)" + ";;JavaScript Files (*.js)"); + + QList<QAxEngineDescriptor>::ConstIterator it; + for (it = engines.begin(); it != engines.end(); ++it) { + QAxEngineDescriptor engine = *it; + if (engine.extension.isEmpty()) + continue; + + allFiles += QLatin1String(" *") + engine.extension; + specialFiles += QLatin1String(";;") + engine.name + QLatin1String(" Files (*") + engine.extension + QLatin1Char(')'); + } + allFiles += QLatin1Char(')'); + + return allFiles + specialFiles + QLatin1String(";;All Files (*.*)"); +} + +/*! + \fn void QAxScriptManager::error(QAxScript *script, int code, const QString &description, + int sourcePosition, const QString &sourceText) + + This signal is emitted when an execution error occurred while + running \a script. + + \a code, \a description, \a sourcePosition and \a sourceText + contain information about the execution error. + + \warning Do not delete \a script in a slot connected to this signal. Use deleteLater() + instead. +*/ + +/*! + \internal + + Returns a pointer to the first QAxScript that knows + about \a function, or 0 if this function is unknown. +*/ +QAxScript *QAxScriptManager::scriptForFunction(const QString &function) const +{ + // check full prototypes if included + if (function.contains(QLatin1Char('('))) { + QHash<QString, QAxScript*>::ConstIterator scriptIt; + for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) { + QAxScript *script = scriptIt.value(); + + if (script->functions(QAxScript::FunctionSignatures).contains(function)) + return script; + } + } + + QString funcName = function; + funcName = funcName.left(funcName.indexOf(QLatin1Char('('))); + // second try, checking only names, not prototypes + QHash<QString, QAxScript*>::ConstIterator scriptIt; + for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) { + QAxScript *script = scriptIt.value(); + + if (script->functions(QAxScript::FunctionNames).contains(funcName)) + return script; + } + + return 0; +} + +/*! + \internal +*/ +void QAxScriptManager::updateScript(QAxScript *script) +{ + QHash<QString, QAxBase*>::ConstIterator objectIt; + for (objectIt = d->objectDict.constBegin(); objectIt != d->objectDict.constEnd(); ++objectIt) { + QString name = objectIt.key(); + + QAxScriptEngine *engine = script->scriptEngine(); + if (engine) + engine->addItem(name); + } +} + +/*! + \internal +*/ +void QAxScriptManager::objectDestroyed(QObject *o) +{ + d->objectDict.take(o->objectName()); +} + +/*! + \internal +*/ +void QAxScriptManager::scriptError(int code, const QString &desc, int spos, const QString &stext) +{ + QAxScript *source = qobject_cast<QAxScript*>(sender()); + emit error(source, code, desc, spos, stext); +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/container/qaxscript.h b/src/activeqt/container/qaxscript.h new file mode 100644 index 0000000..b423376 --- /dev/null +++ b/src/activeqt/container/qaxscript.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXSCRIPT_H +#define QAXSCRIPT_H + +#include <ActiveQt/qaxobject.h> + +struct IActiveScript; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +class QAxBase; +class QAxScript; +class QAxScriptSite; +class QAxScriptEngine; +class QAxScriptManager; +class QAxScriptManagerPrivate; + +class QAxScriptEngine : public QAxObject +{ +public: + enum State { + Uninitialized = 0, + Initialized = 5, + Started = 1, + Connected = 2, + Disconnected = 3, + Closed = 4 + }; + + QAxScriptEngine(const QString &language, QAxScript *script); + ~QAxScriptEngine(); + + bool isValid() const; + bool hasIntrospection() const; + + QString scriptLanguage() const; + + State state() const; + void setState(State st); + + void addItem(const QString &name); + + long queryInterface(const QUuid &, void**) const; + +protected: + bool initialize(IUnknown** ptr); + +private: + QAxScript *script_code; + IActiveScript *engine; + + QString script_language; +}; + +class QAxScript : public QObject +{ + Q_OBJECT + +public: + enum FunctionFlags { + FunctionNames = 0, + FunctionSignatures + }; + + QAxScript(const QString &name, QAxScriptManager *manager); + ~QAxScript(); + + bool load(const QString &code, const QString &language = QString()); + + QStringList functions(FunctionFlags = FunctionNames) const; + + QString scriptCode() const; + QString scriptName() const; + QAxScriptEngine *scriptEngine() const; + + QVariant call(const QString &function, const QVariant &v1 = QVariant(), + const QVariant &v2 = QVariant(), + const QVariant &v3 = QVariant(), + const QVariant &v4 = QVariant(), + const QVariant &v5 = QVariant(), + const QVariant &v6 = QVariant(), + const QVariant &v7 = QVariant(), + const QVariant &v8 = QVariant()); + QVariant call(const QString &function, QList<QVariant> &arguments); + +Q_SIGNALS: + void entered(); + void finished(); + void finished(const QVariant &result); + void finished(int code, const QString &source,const QString &description, const QString &help); + void stateChanged(int state); + void error(int code, const QString &description, int sourcePosition, const QString &sourceText); + +private: + friend class QAxScriptSite; + friend class QAxScriptEngine; + + void updateObjects(); + QAxBase *findObject(const QString &name); + + QString script_name; + QString script_code; + QAxScriptManager *script_manager; + QAxScriptEngine *script_engine; + QAxScriptSite *script_site; +}; + +class QAxScriptManager : public QObject +{ + Q_OBJECT + +public: + QAxScriptManager(QObject *parent = 0); + ~QAxScriptManager(); + + void addObject(QAxBase *object); + void addObject(QObject *object); + + QStringList functions(QAxScript::FunctionFlags = QAxScript::FunctionNames) const; + QStringList scriptNames() const; + QAxScript *script(const QString &name) const; + + QAxScript* load(const QString &code, const QString &name, const QString &language); + QAxScript* load(const QString &file, const QString &name); + + QVariant call(const QString &function, const QVariant &v1 = QVariant(), + const QVariant &v2 = QVariant(), + const QVariant &v3 = QVariant(), + const QVariant &v4 = QVariant(), + const QVariant &v5 = QVariant(), + const QVariant &v6 = QVariant(), + const QVariant &v7 = QVariant(), + const QVariant &v8 = QVariant()); + QVariant call(const QString &function, QList<QVariant> &arguments); + + static bool registerEngine(const QString &name, const QString &extension, const QString &code = QString()); + static QString scriptFileFilter(); + +Q_SIGNALS: + void error(QAxScript *script, int code, const QString &description, int sourcePosition, const QString &sourceText); + +private Q_SLOTS: + void objectDestroyed(QObject *o); + void scriptError(int code, const QString &description, int sourcePosition, const QString &sourceText); + +private: + friend class QAxScript; + QAxScriptManagerPrivate *d; + + void updateScript(QAxScript*); + QAxScript *scriptForFunction(const QString &function) const; +}; + + +// QAxScript inlines + +inline QString QAxScript::scriptCode() const +{ + return script_code; +} + +inline QString QAxScript::scriptName() const +{ + return script_name; +} + +inline QAxScriptEngine *QAxScript::scriptEngine() const +{ + return script_engine; +} + +// QAxScriptEngine inlines + +inline bool QAxScriptEngine::isValid() const +{ + return engine != 0; +} + +inline QString QAxScriptEngine::scriptLanguage() const +{ + return script_language; +} + +// QAxScriptManager inlines + +extern QAxBase *qax_create_object_wrapper(QObject*); + +inline void QAxScriptManager::addObject(QObject *object) +{ + QAxBase *wrapper = qax_create_object_wrapper(object); + if (!wrapper) { + qWarning("QAxScriptMananger::addObject: Class %s not exposed through the QAxFactory", + object->metaObject()->className()); + Q_ASSERT(wrapper); + } + addObject(wrapper); +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXSCRIPT_H diff --git a/src/activeqt/container/qaxscriptwrapper.cpp b/src/activeqt/container/qaxscriptwrapper.cpp new file mode 100644 index 0000000..e2f3109 --- /dev/null +++ b/src/activeqt/container/qaxscriptwrapper.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxobject.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <ActiveQt/qaxfactory.h> + +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +QAxBase *qax_create_object_wrapper(QObject *object) +{ + IDispatch *dispatch = 0; + QAxObject *wrapper = 0; + qAxFactory()->createObjectWrapper(object, &dispatch); + if (dispatch) { + wrapper = new QAxObject(dispatch, object); + wrapper->setObjectName(object->objectName()); + dispatch->Release(); + } + return wrapper; +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/container/qaxselect.cpp b/src/activeqt/container/qaxselect.cpp new file mode 100644 index 0000000..335b73f --- /dev/null +++ b/src/activeqt/container/qaxselect.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxselect.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +class ControlList : public QAbstractListModel +{ +public: + ControlList(QObject *parent=0) + : QAbstractListModel(parent) + { + HKEY classes_key; + RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &classes_key); + if (!classes_key) + return; + + DWORD index = 0; + LONG result = 0; + wchar_t buffer[256]; + DWORD szBuffer = sizeof(buffer) / sizeof(wchar_t); + FILETIME ft; + do { + result = RegEnumKeyEx(classes_key, index, buffer, &szBuffer, 0, 0, 0, &ft); + szBuffer = sizeof(buffer) / sizeof(wchar_t); + if (result == ERROR_SUCCESS) { + HKEY sub_key; + QString clsid = QString::fromWCharArray(buffer); + result = RegOpenKeyEx(classes_key, reinterpret_cast<const wchar_t *>(QString(clsid + "\\Control").utf16()), 0, KEY_READ, &sub_key); + if (result == ERROR_SUCCESS) { + RegCloseKey(sub_key); + RegistryQueryValue(classes_key, buffer, (LPBYTE)buffer, &szBuffer); + QString name = QString::fromWCharArray(buffer); + + controls << name; + clsids.insert(name, clsid); + } + result = ERROR_SUCCESS; + } + szBuffer = sizeof(buffer) / sizeof(wchar_t); + ++index; + } while (result == ERROR_SUCCESS); + RegCloseKey(classes_key); + controls.sort(); + } + + LONG RegistryQueryValue(HKEY hKey, LPCWSTR lpSubKey, LPBYTE lpData, LPDWORD lpcbData) + { + LONG ret = ERROR_FILE_NOT_FOUND; + HKEY hSubKey = NULL; + RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &hSubKey); + if (hSubKey) { + ret = RegQueryValueEx(hSubKey, 0, 0, 0, lpData, lpcbData); + RegCloseKey(hSubKey); + } + return ret; + } + + int rowCount(const QModelIndex & = QModelIndex()) const { return controls.count(); } + QVariant data(const QModelIndex &index, int role) const; + +private: + QStringList controls; + QMap<QString, QString> clsids; +}; + +QVariant ControlList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole) + return controls.at(index.row()); + if (role == Qt::UserRole) + return clsids.value(controls.at(index.row())); + + return QVariant(); +} + +QAxSelect::QAxSelect(QWidget *parent, Qt::WindowFlags f) +: QDialog(parent, f) +{ +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor(Qt::WaitCursor); +#endif + + setupUi(this); + ActiveXList->setModel(new ControlList(this)); + connect(ActiveXList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(on_ActiveXList_clicked(QModelIndex))); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + ActiveXList->setFocus(); + + connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept())); + connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); +} + +void QAxSelect::on_ActiveXList_clicked(const QModelIndex &index) +{ + QVariant clsid = ActiveXList->model()->data(index, Qt::UserRole); + ActiveX->setText(clsid.toString()); +} + +void QAxSelect::on_ActiveXList_doubleClicked(const QModelIndex &index) +{ + QVariant clsid = ActiveXList->model()->data(index, Qt::UserRole); + ActiveX->setText(clsid.toString()); + + accept(); +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/container/qaxselect.h b/src/activeqt/container/qaxselect.h new file mode 100644 index 0000000..063d87e --- /dev/null +++ b/src/activeqt/container/qaxselect.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXSELECT_H +#define QAXSELECT_H + +#include <QtGui/qdialog.h> + +#ifndef QT_NO_WIN_ACTIVEQT +#include "ui_qaxselect.h" +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +class QAxSelect : public QDialog, private Ui::QAxSelect +{ + Q_OBJECT +public: + QAxSelect(QWidget *parent = 0, Qt::WindowFlags f = 0); + + QString clsid() const { return ActiveX->text(); } + +private Q_SLOTS: + void on_ActiveXList_clicked(const QModelIndex &index); + void on_ActiveXList_doubleClicked(const QModelIndex &index); +}; + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXSELECT_H diff --git a/src/activeqt/container/qaxselect.ui b/src/activeqt/container/qaxselect.ui new file mode 100644 index 0000000..b82a543 --- /dev/null +++ b/src/activeqt/container/qaxselect.ui @@ -0,0 +1,174 @@ +<ui version="4.0" stdsetdef="1" > + <class>QAxSelect</class> + <comment>********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <widget class="QDialog" name="QAxSelect" > + <property name="objectName" > + <string notr="true" >QAxSelect</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>439</width> + <height>326</height> + </rect> + </property> + <property name="windowTitle" > + <string>Select ActiveX Control</string> + </property> + <property name="sizeGripEnabled" > + <bool>true</bool> + </property> + <layout class="QGridLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item rowspan="2" row="0" column="1" colspan="1" > + <layout class="QVBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QPushButton" name="buttonOk" > + <property name="objectName" > + <string notr="true" >buttonOk</string> + </property> + <property name="text" > + <string>OK</string> + </property> + <property name="autoDefault" > + <bool>true</bool> + </property> + <property name="default" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="buttonCancel" > + <property name="objectName" > + <string notr="true" >buttonCancel</string> + </property> + <property name="text" > + <string>&Cancel</string> + </property> + <property name="autoDefault" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="Spacer2" > + <property name="sizeHint" > + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="sizeType" > + <enum>Expanding</enum> + </property> + <property name="orientation" > + <enum>Vertical</enum> + </property> + </spacer> + </item> + </layout> + </item> + <item row="0" column="0" > + <widget class="QListView" name="ActiveXList" > + <property name="objectName" > + <string notr="true" >ActiveXList</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLabel" name="TextLabel1" > + <property name="objectName" > + <string notr="true" >TextLabel1</string> + </property> + <property name="text" > + <string>COM &Object:</string> + </property> + <property name="buddy" stdset="0" > + <cstring>ActiveX</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="ActiveX" > + <property name="objectName" > + <string notr="true" >ActiveX</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <includes> + <include location="local" >qaxwidget.h</include> + </includes> +</ui> diff --git a/src/activeqt/container/qaxwidget.cpp b/src/activeqt/container/qaxwidget.cpp new file mode 100644 index 0000000..f69ef95 --- /dev/null +++ b/src/activeqt/container/qaxwidget.cpp @@ -0,0 +1,2257 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxwidget.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <ActiveQt/qaxaggregated.h> + +#include <qabstracteventdispatcher.h> +#include <qapplication.h> +#include <private/qapplication_p.h> +#include <qdockwidget.h> +#include <qevent.h> +#include <qlayout.h> +#include <qmainwindow.h> +#include <qmenu.h> +#include <qmenubar.h> +#include <qmetaobject.h> +#include <qpainter.h> +#include <qpointer.h> +#include <qregexp.h> +#include <quuid.h> +#include <qwhatsthis.h> + +#include <windowsx.h> +#include <ocidl.h> +#include <olectl.h> +#include <docobj.h> + +// #define QAX_DEBUG + +#ifdef QAX_DEBUG +#define AX_DEBUG(x) qDebug(#x); +#else +#define AX_DEBUG(x); +#endif + +// #define QAX_SUPPORT_WINDOWLESS +// #define QAX_SUPPORT_BORDERSPACE + +// missing interface from win32api +#if defined(Q_CC_GNU) && !defined(__MINGW64_VERSION_MAJOR) + DECLARE_INTERFACE_(IOleInPlaceObjectWindowless,IOleInPlaceObject) + { + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetWindow)(THIS_ HWND*) PURE; + STDMETHOD(ContextSensitiveHelp)(THIS_ BOOL) PURE; + STDMETHOD(InPlaceDeactivate)(THIS) PURE; + STDMETHOD(UIDeactivate)(THIS) PURE; + STDMETHOD(SetObjectRects)(THIS_ LPCRECT,LPCRECT) PURE; + STDMETHOD(ReactivateAndUndo)(THIS) PURE; + STDMETHOD(OnWindowMessage)(THIS_ UINT, WPARAM, LPARAM, LRESULT*) PURE; + STDMETHOD(GetDropTarget)(THIS_ IDropTarget**) PURE; + }; +#endif + +#include "../shared/qaxtypes.h" + +QT_BEGIN_NAMESPACE + +/* \class QAxHostWidget + \brief The QAxHostWidget class is the actual container widget. + + \internal +*/ +class QAxHostWidget : public QWidget +{ + friend class QAxClientSite; +public: + Q_OBJECT_CHECK + QAxHostWidget(QWidget *parent, QAxClientSite *ax); + ~QAxHostWidget(); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + int qt_metacall(QMetaObject::Call, int isignal, void **argv); + void* qt_metacast(const char *clname); + + inline QAxClientSite *clientSite() const + { + return axhost; + } + +protected: + bool winEvent(MSG *msg, long *result); + bool event(QEvent *e); + bool eventFilter(QObject *o, QEvent *e); + void resizeEvent(QResizeEvent *e); + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void paintEvent(QPaintEvent *e); + void showEvent(QShowEvent *e); + QPaintEngine* paintEngine() const + { + return 0; + } + +private: + void resizeObject(); + + int setFocusTimer; + bool hasFocus; + QAxClientSite *axhost; +}; + +/* \class QAxClientSite + \brief The QAxClientSite class implements the client site interfaces. + + \internal +*/ +class QAxClientSite : public IDispatch, + public IOleClientSite, + public IOleControlSite, +#ifdef QAX_SUPPORT_WINDOWLESS + public IOleInPlaceSiteWindowless, +#else + public IOleInPlaceSite, +#endif + public IOleInPlaceFrame, + public IOleDocumentSite, + public IAdviseSink +{ + friend class QAxHostWidget; +public: + QAxClientSite(QAxWidget *c); + virtual ~QAxClientSite(); + + bool activateObject(bool initialized, const QByteArray &data); + + void releaseAll(); + void deactivate(); + inline void reset(QWidget *p) + { + if (widget == p) + widget = 0; + else if (host == p) + host = 0; + } + + inline IOleInPlaceActiveObject *inPlaceObject() const + { + return m_spInPlaceActiveObject; + } + + inline HRESULT doVerb(LONG index) + { + if (!m_spOleObject) + return E_NOTIMPL; + if (!host) + return OLE_E_NOT_INPLACEACTIVE; + + RECT rcPos = { host->x(), host->y(), host->x()+host->width(), host->y()+host->height() }; + return m_spOleObject->DoVerb(index, 0, this, 0, host->winId(), &rcPos); + } + + // IUnknown + unsigned long WINAPI AddRef(); + unsigned long WINAPI Release(); + STDMETHOD(QueryInterface)(REFIID iid, void **iface); + + // IDispatch + HRESULT __stdcall GetTypeInfoCount(unsigned int *) { return E_NOTIMPL; } + HRESULT __stdcall GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_NOTIMPL; } + HRESULT __stdcall GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *) { return E_NOTIMPL; } + HRESULT __stdcall Invoke(DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr); + void emitAmbientPropertyChange(DISPID dispid); + + // IOleClientSite + STDMETHOD(SaveObject)(); + STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk); + STDMETHOD(GetContainer)(LPOLECONTAINER FAR* ppContainer); + STDMETHOD(ShowObject)(); + STDMETHOD(OnShowWindow)(BOOL fShow); + STDMETHOD(RequestNewObjectLayout)(); + + // IOleControlSite + STDMETHOD(OnControlInfoChanged)(); + STDMETHOD(LockInPlaceActive)(BOOL fLock); + STDMETHOD(GetExtendedControl)(IDispatch** ppDisp); + STDMETHOD(TransformCoords)(POINTL* pPtlHimetric, POINTF* pPtfContainer, DWORD dwFlags); + STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, DWORD grfModifiers); + STDMETHOD(OnFocus)(BOOL fGotFocus); + STDMETHOD(ShowPropertyFrame)(); + + // IOleWindow + STDMETHOD(GetWindow)(HWND *phwnd); + STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode); + + // IOleInPlaceSite + STDMETHOD(CanInPlaceActivate)(); + STDMETHOD(OnInPlaceActivate)(); + STDMETHOD(OnUIActivate)(); + STDMETHOD(GetWindowContext)(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo); + STDMETHOD(Scroll)(SIZE scrollExtant); + STDMETHOD(OnUIDeactivate)(BOOL fUndoable); + STDMETHOD(OnInPlaceDeactivate)(); + STDMETHOD(DiscardUndoState)(); + STDMETHOD(DeactivateAndUndo)(); + STDMETHOD(OnPosRectChange)(LPCRECT lprcPosRect); + +#ifdef QAX_SUPPORT_WINDOWLESS +// IOleInPlaceSiteEx ### + STDMETHOD(OnInPlaceActivateEx)(BOOL* /*pfNoRedraw*/, DWORD /*dwFlags*/) + { + return S_OK; + } + STDMETHOD(OnInPlaceDeactivateEx)(BOOL /*fNoRedraw*/) + { + return S_OK; + } + STDMETHOD(RequestUIActivate)() + { + return S_OK; + } + +// IOleInPlaceSiteWindowless ### + STDMETHOD(CanWindowlessActivate)() + { + return S_OK; + } + STDMETHOD(GetCapture)() + { + return S_FALSE; + } + STDMETHOD(SetCapture)(BOOL /*fCapture*/) + { + return S_FALSE; + } + STDMETHOD(GetFocus)() + { + return S_FALSE; + } + STDMETHOD(SetFocus)(BOOL /*fCapture*/) + { + return S_FALSE; + } + STDMETHOD(GetDC)(LPCRECT /*pRect*/, DWORD /*grfFlags*/, HDC *phDC) + { + *phDC = 0; + return S_OK; + } + STDMETHOD(ReleaseDC)(HDC hDC) + { + ::ReleaseDC(widget->winId(), hDC); + return S_OK; + } + STDMETHOD(InvalidateRect)(LPCRECT pRect, BOOL fErase) + { + ::InvalidateRect(host->winId(), pRect, fErase); + return S_OK; + } + STDMETHOD(InvalidateRgn)(HRGN hRGN, BOOL fErase) + { + ::InvalidateRgn(host->winId(), hRGN, fErase); + return S_OK; + } + STDMETHOD(ScrollRect)(int /*dx*/, int /*dy*/, LPCRECT /*pRectScroll*/, LPCRECT /*pRectClip*/) + { + return S_OK; + } + STDMETHOD(AdjustRect)(LPRECT /*prc*/) + { + return S_OK; + } +#ifdef Q_CC_GNU // signature incorrect in win32api + STDMETHOD(AdjustRect)(LPCRECT /*prc*/) + { + RECT rect; + return AdjustRect(&rect); + } +#endif + + STDMETHOD(OnDefWindowMessage)(UINT /*msg*/, WPARAM /*wPara*/, LPARAM /*lParam*/, LRESULT* /*plResult*/) + { + return S_FALSE; + } +#endif + + // IOleInPlaceFrame + STDMETHOD(InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)); + STDMETHOD(SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)); + STDMETHOD(RemoveMenus(HMENU hmenuShared)); + STDMETHOD(SetStatusText(LPCOLESTR pszStatusText)); + STDMETHOD(EnableModeless(BOOL fEnable)); + STDMETHOD(TranslateAccelerator(LPMSG lpMsg, WORD grfModifiers)); + + // IOleInPlaceUIWindow + STDMETHOD(GetBorder(LPRECT lprectBorder)); + STDMETHOD(RequestBorderSpace(LPCBORDERWIDTHS pborderwidths)); + STDMETHOD(SetBorderSpace(LPCBORDERWIDTHS pborderwidths)); + STDMETHOD(SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)); + + // IOleDocumentSite + STDMETHOD(ActivateMe(IOleDocumentView *pViewToActivate)); + + // IAdviseSink + STDMETHOD_(void, OnDataChange)(FORMATETC* /*pFormatetc*/, STGMEDIUM* /*pStgmed*/) + { + AX_DEBUG(QAxClientSite::OnDataChange); + } + STDMETHOD_(void, OnViewChange)(DWORD /*dwAspect*/, LONG /*lindex*/) + { + AX_DEBUG(QAxClientSite::OnViewChange); + } + STDMETHOD_(void, OnRename)(IMoniker* /*pmk*/) + { + } + STDMETHOD_(void, OnSave)() + { + } + STDMETHOD_(void, OnClose)() + { + } + + QSize sizeHint() const { return sizehint; } + QSize minimumSizeHint() const; + inline void resize(QSize sz) { if (host) host->resize(sz); } + + bool translateKeyEvent(int message, int keycode) const + { + if (!widget) + return false; + return widget->translateKeyEvent(message, keycode); + } + + int qt_metacall(QMetaObject::Call, int isignal, void **argv); + void windowActivationChange(); + + bool eventTranslated : 1; + +private: +#if !defined(Q_WS_WINCE) + struct OleMenuItem { + OleMenuItem(HMENU hm = 0, int ID = 0, QMenu *menu = 0) + : hMenu(hm), id(ID), subMenu(menu) + {} + HMENU hMenu; + int id; + QMenu *subMenu; + }; + QMenu *generatePopup(HMENU subMenu, QWidget *parent); +#endif + + IOleObject *m_spOleObject; + IOleControl *m_spOleControl; + IOleInPlaceObjectWindowless *m_spInPlaceObject; + IOleInPlaceActiveObject *m_spInPlaceActiveObject; + IOleDocumentView *m_spActiveView; + + QAxAggregated *aggregatedObject; + + bool inPlaceObjectWindowless :1; + bool inPlaceModelessEnabled :1; + bool canHostDocument : 1; + + DWORD m_dwOleObject; +#if !defined(Q_WS_WINCE) + HWND m_menuOwner; +#endif + CONTROLINFO control_info; + + QSize sizehint; + unsigned long ref; + QAxWidget *widget; + QAxHostWidget *host; +#if !defined(Q_WS_WINCE) + QPointer<QMenuBar> menuBar; + QMap<QAction*,OleMenuItem> menuItemMap; +#endif +}; + +static const ushort mouseTbl[] = { + WM_MOUSEMOVE, QEvent::MouseMove, 0, + WM_LBUTTONDOWN, QEvent::MouseButtonPress, Qt::LeftButton, + WM_LBUTTONUP, QEvent::MouseButtonRelease, Qt::LeftButton, + WM_LBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton, + WM_RBUTTONDOWN, QEvent::MouseButtonPress, Qt::RightButton, + WM_RBUTTONUP, QEvent::MouseButtonRelease, Qt::RightButton, + WM_RBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton, + WM_MBUTTONDOWN, QEvent::MouseButtonPress, Qt::MidButton, + WM_MBUTTONUP, QEvent::MouseButtonRelease, Qt::MidButton, + WM_MBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton, + 0, 0, 0 +}; + +static Qt::MouseButtons translateMouseButtonState(int s) +{ + Qt::MouseButtons bst = 0; + if (s & MK_LBUTTON) + bst |= Qt::LeftButton; + if (s & MK_MBUTTON) + bst |= Qt::MidButton; + if (s & MK_RBUTTON) + bst |= Qt::RightButton; + + return bst; +} + +static Qt::KeyboardModifiers translateModifierState(int s) +{ + Qt::KeyboardModifiers bst = 0; + if (s & MK_SHIFT) + bst |= Qt::ShiftModifier; + if (s & MK_CONTROL) + bst |= Qt::ControlModifier; + if (GetKeyState(VK_MENU) < 0) + bst |= Qt::AltModifier; + + return bst; +} + +static QAbstractEventDispatcher::EventFilter previous_filter = 0; +#if QT_VERSION >= 0x050000 +#error "Fix QAbstractEventDispatcher::setEventFilter" +#endif +#if defined(Q_WS_WINCE) +static int filter_ref = 0; +#else +static const wchar_t *qaxatom = L"QAxContainer4_Atom"; +#endif + +// The filter procedure listening to user interaction on the control +bool axc_FilterProc(void *m) +{ + MSG *msg = (MSG*)m; + const uint message = msg->message; + if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || (message >= WM_KEYFIRST && message <= WM_KEYLAST)) { + HWND hwnd = msg->hwnd; + QAxWidget *ax = 0; + QAxHostWidget *host = 0; + while (!host && hwnd) { + QWidget *widget = QWidget::find(hwnd); + if (widget && widget->inherits("QAxHostWidget")) + host = qobject_cast<QAxHostWidget*>(widget); + hwnd = ::GetParent(hwnd); + } + if (host) + ax = qobject_cast<QAxWidget*>(host->parentWidget()); + if (ax && msg->hwnd != host->winId()) { + if (message >= WM_KEYFIRST && message <= WM_KEYLAST) { + QAxClientSite *site = host->clientSite(); + site->eventTranslated = true; // reset in QAxClientSite::TranslateAccelerator + HRESULT hres = S_FALSE; + if (site && site->inPlaceObject() && site->translateKeyEvent(msg->message, msg->wParam)) + hres = site->inPlaceObject()->TranslateAccelerator(msg); + // if the object calls our TranslateAccelerator implementation, then continue with normal event processing + // otherwise the object has translated the accelerator, and the event should be stopped + if (site->eventTranslated && hres == S_OK) + return true; + } else { + int i; + for (i = 0; (UINT)mouseTbl[i] != message && mouseTbl[i]; i += 3) + ; + + if (mouseTbl[i]) { + QEvent::Type type = (QEvent::Type)mouseTbl[++i]; + int button = mouseTbl[++i]; + if (type != QEvent::MouseMove || ax->hasMouseTracking() || button) { + if (type == QEvent::MouseMove) + button = 0; + + DWORD ol_pos = GetMessagePos(); + QPoint gpos(GET_X_LPARAM(ol_pos), GET_Y_LPARAM(ol_pos)); + QPoint pos = ax->mapFromGlobal(gpos); + + QMouseEvent e(type, pos, gpos, (Qt::MouseButton)button, + translateMouseButtonState(msg->wParam), + translateModifierState(msg->wParam)); + QApplication::sendEvent(ax, &e); + } + } + } + } + } + + if (previous_filter) + return previous_filter(m); + + return false; +} + +QAxClientSite::QAxClientSite(QAxWidget *c) +: eventTranslated(true), ref(1), widget(c), host(0) +{ + aggregatedObject = widget->createAggregate(); + if (aggregatedObject) { + aggregatedObject->controlling_unknown = (IUnknown*)(IDispatch*)this; + aggregatedObject->the_object = c; + } + + m_spOleObject = 0; + m_spOleControl = 0; + m_spInPlaceObject = 0; + m_spInPlaceActiveObject = 0; + m_spActiveView = 0; + + inPlaceObjectWindowless = false; + inPlaceModelessEnabled = true; + canHostDocument = false; + + m_dwOleObject = 0; +#if !defined(Q_WS_WINCE) + m_menuOwner = 0; + menuBar = 0; +#endif + memset(&control_info, 0, sizeof(control_info)); +} + +bool QAxClientSite::activateObject(bool initialized, const QByteArray &data) +{ + if (!host) + host = new QAxHostWidget(widget, this); + + bool showHost = false; + HRESULT hr = S_OK; + if (!m_spOleObject) + widget->queryInterface(IID_IOleObject, (void**)&m_spOleObject); + if (m_spOleObject) { + DWORD dwMiscStatus = 0; + m_spOleObject->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus); + +#if !defined(Q_OS_WINCE) + IOleDocument *document = 0; + m_spOleObject->QueryInterface(IID_IOleDocument, (void**)&document); + if (document) { + IPersistStorage *persistStorage = 0; + document->QueryInterface(IID_IPersistStorage, (void**)&persistStorage); + if (persistStorage) { + // try to activate as document server + IStorage *storage = 0; + ILockBytes * bytes = 0; + HRESULT hres = ::CreateILockBytesOnHGlobal(0, TRUE, &bytes); + hres = ::StgCreateDocfileOnILockBytes(bytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &storage); + + persistStorage->InitNew(storage); + persistStorage->Release(); + canHostDocument = true; + storage->Release(); + bytes->Release(); + + m_spOleObject->SetClientSite(this); + OleRun(m_spOleObject); + } + document->Release(); + } +#endif + + if (!canHostDocument) { + // activate as control + if(dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST) + m_spOleObject->SetClientSite(this); + + if (!initialized) { + IPersistStreamInit *spPSI = 0; + m_spOleObject->QueryInterface(IID_IPersistStreamInit, (void**)&spPSI); + if (spPSI) { + if (data.length()) { + IStream *pStream = 0; + HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, data.length()); + if (hGlobal) { + BYTE *pStByte = (BYTE *)GlobalLock(hGlobal); + if (pStByte) + memcpy(pStByte, data.data(), data.length()); + GlobalUnlock(hGlobal); + if (SUCCEEDED(CreateStreamOnHGlobal(hGlobal, TRUE, &pStream))) { + spPSI->Load(pStream); + pStream->Release(); + } + GlobalFree(hGlobal); + } + } else { + spPSI->InitNew(); + } + spPSI->Release(); + } else if (data.length()) { //try initializing using a IPersistStorage + IPersistStorage *spPS = 0; + m_spOleObject->QueryInterface( IID_IPersistStorage, (void**)&spPS ); + if (spPS) { + HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, data.length()); + if (hGlobal) { +#if !defined(Q_OS_WINCE) + BYTE* pbData = (BYTE*)GlobalLock(hGlobal); + if (pbData) + memcpy(pbData, data.data(), data.length()); + GlobalUnlock(hGlobal); + // open an IStorage on the data and pass it to Load + LPLOCKBYTES pLockBytes = 0; + if (SUCCEEDED(CreateILockBytesOnHGlobal(hGlobal, TRUE, &pLockBytes))) { + LPSTORAGE pStorage = 0; + if (SUCCEEDED(StgOpenStorageOnILockBytes(pLockBytes, 0, + STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStorage))) { + spPS->Load(pStorage); + pStorage->Release(); + } + pLockBytes->Release(); + } + GlobalFree(hGlobal); +#endif + } + spPS->Release(); + } + } + } + + if(!(dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)) + m_spOleObject->SetClientSite(this); + } + + IViewObject *spViewObject = 0; + m_spOleObject->QueryInterface(IID_IViewObject, (void**) &spViewObject); + + m_spOleObject->Advise(this, &m_dwOleObject); + IAdviseSink *spAdviseSink = 0; + QueryInterface(IID_IAdviseSink, (void**)&spAdviseSink); + if (spAdviseSink && spViewObject) { + if (spViewObject) + spViewObject->SetAdvise(DVASPECT_CONTENT, 0, spAdviseSink); + spAdviseSink->Release(); + } + if (spViewObject) + spViewObject->Release(); + + m_spOleObject->SetHostNames(OLESTR("AXWIN"), 0); + + if (!(dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)) { + SIZEL hmSize; + hmSize.cx = MAP_PIX_TO_LOGHIM(250, widget->logicalDpiX()); + hmSize.cy = MAP_PIX_TO_LOGHIM(250, widget->logicalDpiY()); + + m_spOleObject->SetExtent(DVASPECT_CONTENT, &hmSize); + m_spOleObject->GetExtent(DVASPECT_CONTENT, &hmSize); + + sizehint.setWidth(MAP_LOGHIM_TO_PIX(hmSize.cx, widget->logicalDpiX())); + sizehint.setHeight(MAP_LOGHIM_TO_PIX(hmSize.cy, widget->logicalDpiY())); + showHost = true; + } else { + sizehint = QSize(0, 0); + host->hide(); + } + if (!(dwMiscStatus & OLEMISC_NOUIACTIVATE)) { + host->setFocusPolicy(Qt::StrongFocus); + } else { + host->setFocusPolicy(Qt::NoFocus); + } + + RECT rcPos = { host->x(), host->y(), host->x()+sizehint.width(), host->y()+sizehint.height() }; + + hr = m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, 0, (IOleClientSite*)this, 0, host->winId(), &rcPos); + + if (!m_spOleControl) + m_spOleObject->QueryInterface(IID_IOleControl, (void**)&m_spOleControl); + if (m_spOleControl) { + m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_BACKCOLOR); + m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_FORECOLOR); + m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_FONT); + m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_USERMODE); + + control_info.cb = sizeof(control_info); + m_spOleControl->GetControlInfo(&control_info); + } + + BSTR userType; + HRESULT result = m_spOleObject->GetUserType(USERCLASSTYPE_SHORT, &userType); + if (result == S_OK) { + widget->setWindowTitle(QString::fromWCharArray(userType)); + CoTaskMemFree(userType); + } + } else { + IObjectWithSite *spSite = 0; + widget->queryInterface(IID_IObjectWithSite, (void**)&spSite); + if (spSite) { + spSite->SetSite((IUnknown*)(IDispatch*)this); + spSite->Release(); + } + } + + host->resize(widget->size()); + if (showHost) + host->show(); + + if (host->focusPolicy() != Qt::NoFocus) { + widget->setFocusProxy(host); + widget->setFocusPolicy(host->focusPolicy()); + } + + return true; +} + +QAxClientSite::~QAxClientSite() +{ + if (host) { + host->axhost = 0; + } + + if (aggregatedObject) + aggregatedObject->the_object = 0; + delete aggregatedObject; + delete host; +} + +void QAxClientSite::releaseAll() +{ + if (m_spOleObject) { + m_spOleObject->SetClientSite(0); + m_spOleObject->Unadvise(m_dwOleObject); + m_spOleObject->Release(); + } + m_spOleObject = 0; + if (m_spOleControl) m_spOleControl->Release(); + m_spOleControl = 0; + if (m_spInPlaceObject) m_spInPlaceObject->Release(); + m_spInPlaceObject = 0; + if (m_spInPlaceActiveObject) m_spInPlaceActiveObject->Release(); + m_spInPlaceActiveObject = 0; + + inPlaceObjectWindowless = false; +} + +void QAxClientSite::deactivate() +{ + if (m_spInPlaceObject) m_spInPlaceObject->InPlaceDeactivate(); + // if this assertion fails the control didn't call OnInPlaceDeactivate + Q_ASSERT(m_spInPlaceObject == 0); +} + +//**** IUnknown +unsigned long WINAPI QAxClientSite::AddRef() +{ + return ++ref; +} + +unsigned long WINAPI QAxClientSite::Release() +{ + if (!--ref) { + delete this; + return 0; + } + return ref; +} + +HRESULT WINAPI QAxClientSite::QueryInterface(REFIID iid, void **iface) +{ + *iface = 0; + + if (iid == IID_IUnknown) { + *iface = (IUnknown*)(IDispatch*)this; + } else { + HRESULT res = S_OK; + if (aggregatedObject) + res = aggregatedObject->queryInterface(iid, iface); + if (*iface) + return res; + } + + if (!(*iface)) { + if (iid == IID_IDispatch) + *iface = (IDispatch*)this; + else if (iid == IID_IOleClientSite) + *iface = (IOleClientSite*)this; + else if (iid == IID_IOleControlSite) + *iface = (IOleControlSite*)this; + else if (iid == IID_IOleWindow) + *iface = (IOleWindow*)(IOleInPlaceSite*)this; + else if (iid == IID_IOleInPlaceSite) + *iface = (IOleInPlaceSite*)this; +#ifdef QAX_SUPPORT_WINDOWLESS + else if (iid == IID_IOleInPlaceSiteEx) + *iface = (IOleInPlaceSiteEx*)this; + else if (iid == IID_IOleInPlaceSiteWindowless) + *iface = (IOleInPlaceSiteWindowless*)this; +#endif + else if (iid == IID_IOleInPlaceFrame) + *iface = (IOleInPlaceFrame*)this; + else if (iid == IID_IOleInPlaceUIWindow) + *iface = (IOleInPlaceUIWindow*)this; + else if (iid == IID_IOleDocumentSite && canHostDocument) + *iface = (IOleDocumentSite*)this; + else if (iid == IID_IAdviseSink) + *iface = (IAdviseSink*)this; + } + if (!*iface) + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +bool qax_runsInDesignMode = false; + +//**** IDispatch +HRESULT WINAPI QAxClientSite::Invoke(DISPID dispIdMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD /*wFlags*/, + DISPPARAMS * /*pDispParams*/, + VARIANT *pVarResult, + EXCEPINFO * /*pExcepInfo*/, + UINT * /*puArgErr*/) +{ + if (!pVarResult) + return E_POINTER; + if (!widget || !host) + return E_UNEXPECTED; + + switch(dispIdMember) { + case DISPID_AMBIENT_USERMODE: + pVarResult->vt = VT_BOOL; + pVarResult->boolVal = !qax_runsInDesignMode; + return S_OK; + + case DISPID_AMBIENT_AUTOCLIP: + case DISPID_AMBIENT_SUPPORTSMNEMONICS: + pVarResult->vt = VT_BOOL; + pVarResult->boolVal = true; + return S_OK; + + case DISPID_AMBIENT_SHOWHATCHING: + case DISPID_AMBIENT_SHOWGRABHANDLES: + case DISPID_AMBIENT_DISPLAYASDEFAULT: + case DISPID_AMBIENT_MESSAGEREFLECT: + pVarResult->vt = VT_BOOL; + pVarResult->boolVal = false; + return S_OK; + + case DISPID_AMBIENT_DISPLAYNAME: + pVarResult->vt = VT_BSTR; + pVarResult->bstrVal = QStringToBSTR(widget->windowTitle()); + return S_OK; + + case DISPID_AMBIENT_FONT: + QVariantToVARIANT(widget->font(), *pVarResult); + return S_OK; + + case DISPID_AMBIENT_BACKCOLOR: + pVarResult->vt = VT_UI4; + pVarResult->lVal = QColorToOLEColor(widget->palette().color(widget->backgroundRole())); + return S_OK; + + case DISPID_AMBIENT_FORECOLOR: + pVarResult->vt = VT_UI4; + pVarResult->lVal = QColorToOLEColor(widget->palette().color(widget->foregroundRole())); + return S_OK; + + case DISPID_AMBIENT_UIDEAD: + pVarResult->vt = VT_BOOL; + pVarResult->boolVal = !widget->isEnabled(); + return S_OK; + + default: + break; + } + + return DISP_E_MEMBERNOTFOUND; +} + +void QAxClientSite::emitAmbientPropertyChange(DISPID dispid) +{ + if (m_spOleControl) + m_spOleControl->OnAmbientPropertyChange(dispid); +} + +//**** IOleClientSite +HRESULT WINAPI QAxClientSite::SaveObject() +{ + return E_NOTIMPL; +} + +HRESULT WINAPI QAxClientSite::GetMoniker(DWORD, DWORD, IMoniker **ppmk) +{ + if (!ppmk) + return E_POINTER; + + *ppmk = 0; + return E_NOTIMPL; +} + +HRESULT WINAPI QAxClientSite::GetContainer(LPOLECONTAINER *ppContainer) +{ + if (!ppContainer) + return E_POINTER; + + *ppContainer = 0; + return E_NOINTERFACE; +} + +HRESULT WINAPI QAxClientSite::ShowObject() +{ + return S_OK; +} + +HRESULT WINAPI QAxClientSite::OnShowWindow(BOOL /*fShow*/) +{ + return S_OK; +} + +HRESULT WINAPI QAxClientSite::RequestNewObjectLayout() +{ + return E_NOTIMPL; +} + +//**** IOleControlSite +HRESULT WINAPI QAxClientSite::OnControlInfoChanged() +{ + if (m_spOleControl) + m_spOleControl->GetControlInfo(&control_info); + + return S_OK; +} + +HRESULT WINAPI QAxClientSite::LockInPlaceActive(BOOL /*fLock*/) +{ + AX_DEBUG(QAxClientSite::LockInPlaceActive); + return S_OK; +} + +HRESULT WINAPI QAxClientSite::GetExtendedControl(IDispatch** ppDisp) +{ + if (!ppDisp) + return E_POINTER; + + *ppDisp = 0; + return E_NOTIMPL; +} + +HRESULT WINAPI QAxClientSite::TransformCoords(POINTL* /*pPtlHimetric*/, POINTF* /*pPtfContainer*/, DWORD /*dwFlags*/) +{ + return S_OK; +} + +HRESULT WINAPI QAxClientSite::TranslateAccelerator(LPMSG lpMsg, DWORD /*grfModifiers*/) +{ + if (lpMsg->message == WM_KEYDOWN && !lpMsg->wParam) + return S_OK; + + bool ActiveQtDetected = false; + bool fromInProcServer = false; +#ifdef GWLP_USERDATA + LONG_PTR serverType = GetWindowLongPtr(lpMsg->hwnd, GWLP_USERDATA); +#else + LONG serverType = GetWindowLong(lpMsg->hwnd, GWL_USERDATA); +#endif + if (serverType == QAX_INPROC_SERVER) { + ActiveQtDetected = true; + fromInProcServer = true; + } else if (serverType == QAX_OUTPROC_SERVER) { + ActiveQtDetected = true; + fromInProcServer = false; + } + + eventTranslated = false; + if (!ActiveQtDetected || !fromInProcServer) { + // if the request is coming from an out-of-proc server or a non ActiveQt server, + // we send the message to the host window. This will make sure this key event + // comes to Qt for processing. + SendMessage(host->winId(), lpMsg->message, lpMsg->wParam, lpMsg->lParam); + if (ActiveQtDetected && !fromInProcServer) { + // ActiveQt based servers will need further processing of the event + // (eg. <SPACE> key for a checkbox), so we return false. + return S_FALSE; + } + } + // ActiveQt based in-processes-servers will handle the event properly, so + // we don't need to send this key event to the host. + return S_OK; +} + +HRESULT WINAPI QAxClientSite::OnFocus(BOOL bGotFocus) +{ + AX_DEBUG(QAxClientSite::OnFocus); + if (host) { + host->hasFocus = bGotFocus; + qApp->removeEventFilter(host); + if (bGotFocus) + qApp->installEventFilter(host); + } + return S_OK; +} + +HRESULT WINAPI QAxClientSite::ShowPropertyFrame() +{ + return E_NOTIMPL; +} + +//**** IOleWindow +HRESULT WINAPI QAxClientSite::GetWindow(HWND *phwnd) +{ + if (!phwnd) + return E_POINTER; + + *phwnd = host->winId(); + return S_OK; +} + +HRESULT WINAPI QAxClientSite::ContextSensitiveHelp(BOOL fEnterMode) +{ + if (fEnterMode) + QWhatsThis::enterWhatsThisMode(); + else + QWhatsThis::leaveWhatsThisMode(); + + return S_OK; +} + +//**** IOleInPlaceSite +HRESULT WINAPI QAxClientSite::CanInPlaceActivate() +{ + AX_DEBUG(QAxClientSite::CanInPlaceActivate); + return S_OK; +} + +HRESULT WINAPI QAxClientSite::OnInPlaceActivate() +{ + AX_DEBUG(QAxClientSite::OnInPlaceActivate); +#if !defined(Q_OS_WINCE) + OleLockRunning(m_spOleObject, true, false); +#endif + if (!m_spInPlaceObject) { +/* ### disabled for now + m_spOleObject->QueryInterface(IID_IOleInPlaceObjectWindowless, (void**) &m_spInPlaceObject); +*/ + if (m_spInPlaceObject) { + inPlaceObjectWindowless = true; + } else { + inPlaceObjectWindowless = false; + m_spOleObject->QueryInterface(IID_IOleInPlaceObject, (void**) &m_spInPlaceObject); + } + } + + return S_OK; +} + +HRESULT WINAPI QAxClientSite::OnUIActivate() +{ + AX_DEBUG(QAxClientSite::OnUIActivate); + return S_OK; +} + +HRESULT WINAPI QAxClientSite::GetWindowContext(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + if (!ppFrame || !ppDoc || !lprcPosRect || !lprcClipRect || !lpFrameInfo) + return E_POINTER; + + QueryInterface(IID_IOleInPlaceFrame, (void**)ppFrame); + QueryInterface(IID_IOleInPlaceUIWindow, (void**)ppDoc); + + ::GetClientRect(host->winId(), lprcPosRect); + ::GetClientRect(host->winId(), lprcClipRect); + + lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO); + lpFrameInfo->fMDIApp = false; + lpFrameInfo->haccel = 0; + lpFrameInfo->cAccelEntries = 0; + lpFrameInfo->hwndFrame = widget ? widget->window()->winId() : 0; + + return S_OK; +} + +HRESULT WINAPI QAxClientSite::Scroll(SIZE /*scrollExtant*/) +{ + return S_FALSE; +} + +HRESULT WINAPI QAxClientSite::OnUIDeactivate(BOOL) +{ + AX_DEBUG(QAxClientSite::OnUIDeactivate); + if (host && host->hasFocus) { + qApp->removeEventFilter(host); + host->hasFocus = false; + } + return S_OK; +} + +HRESULT WINAPI QAxClientSite::OnInPlaceDeactivate() +{ + AX_DEBUG(QAxClientSite::OnInPlaceDeactivate); + if (m_spInPlaceObject) + m_spInPlaceObject->Release(); + m_spInPlaceObject = 0; + inPlaceObjectWindowless = false; +#if !defined(Q_OS_WINCE) + OleLockRunning(m_spOleObject, false, false); +#endif + + return S_OK; +} + +HRESULT WINAPI QAxClientSite::DiscardUndoState() +{ + return S_OK; +} + +HRESULT WINAPI QAxClientSite::DeactivateAndUndo() +{ + if (m_spInPlaceObject) + m_spInPlaceObject->UIDeactivate(); + + return S_OK; +} + +HRESULT WINAPI QAxClientSite::OnPosRectChange(LPCRECT /*lprcPosRect*/) +{ + AX_DEBUG(QAxClientSite::OnPosRectChange); + // ### + return S_OK; +} + +//**** IOleInPlaceFrame +#if defined(Q_WS_WINCE) +HRESULT WINAPI QAxClientSite::InsertMenus(HMENU /*hmenuShared*/, LPOLEMENUGROUPWIDTHS /*lpMenuWidths*/) +{ + return E_NOTIMPL; +#else +HRESULT WINAPI QAxClientSite::InsertMenus(HMENU /*hmenuShared*/, LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + AX_DEBUG(QAxClientSite::InsertMenus); + QMenuBar *mb = menuBar; + if (!mb) + mb = widget->window()->findChild<QMenuBar*>(); + if (!mb) + return E_NOTIMPL; + menuBar = mb; + + QMenu *fileMenu = 0; + QMenu *viewMenu = 0; + QMenu *windowMenu = 0; + QList<QAction*> actions = menuBar->actions(); + for (int i = 0; i < actions.count(); ++i) { + QAction *action = actions.at(i); + QString text = action->text().remove(QLatin1Char('&')); + if (text == QLatin1String("File")) { + fileMenu = action->menu(); + } else if (text == QLatin1String("View")) { + viewMenu = action->menu(); + } else if (text == QLatin1String("Window")) { + windowMenu = action->menu(); + } + } + if (fileMenu) + lpMenuWidths->width[0] = fileMenu->actions().count(); + if (viewMenu) + lpMenuWidths->width[2] = viewMenu->actions().count(); + if (windowMenu) + lpMenuWidths->width[4] = windowMenu->actions().count(); + + return S_OK; +#endif +} + +static int menuItemEntry(HMENU menu, int index, MENUITEMINFO item, QString &text, QPixmap &/*icon*/) +{ + if (item.fType == MFT_STRING && item.cch) { + wchar_t *titlebuf = new wchar_t[item.cch + 1]; + item.dwTypeData = titlebuf; + item.cch++; + ::GetMenuItemInfo(menu, index, true, &item); + text = QString::fromWCharArray(titlebuf); + delete [] titlebuf; + return MFT_STRING; + } +#if 0 + else if (item.fType == MFT_BITMAP) { + HBITMAP hbm = (HBITMAP)LOWORD(item.hbmpItem); + SIZE bmsize; + GetBitmapDimensionEx(hbm, &bmsize); + QPixmap pixmap(1,1); + QSize sz(MAP_LOGHIM_TO_PIX(bmsize.cx, pixmap.logicalDpiX()), + MAP_LOGHIM_TO_PIX(bmsize.cy, pixmap.logicalDpiY())); + + pixmap.resize(bmsize.cx, bmsize.cy); + if (!pixmap.isNull()) { + HDC hdc = ::CreateCompatibleDC(pixmap.handle()); + ::SelectObject(hdc, hbm); + BOOL res = ::BitBlt(pixmap.handle(), 0, 0, pixmap.width(), pixmap.height(), hdc, 0, 0, SRCCOPY); + ::DeleteObject(hdc); + } + + icon = pixmap; + } +#endif + return -1; +} + +#if !defined(Q_OS_WINCE) +QMenu *QAxClientSite::generatePopup(HMENU subMenu, QWidget *parent) +{ + QMenu *popup = 0; + int count = GetMenuItemCount(subMenu); + if (count) + popup = new QMenu(parent); + for (int i = 0; i < count; ++i) { + MENUITEMINFO item; + memset(&item, 0, sizeof(MENUITEMINFO)); + item.cbSize = sizeof(MENUITEMINFO); + item.fMask = MIIM_ID | MIIM_TYPE | MIIM_SUBMENU; + ::GetMenuItemInfo(subMenu, i, true, &item); + + QAction *action = 0; + QMenu *popupMenu = 0; + if (item.fType == MFT_SEPARATOR) { + action = popup->addSeparator(); + } else { + QString text; + QPixmap icon; + QKeySequence accel; + popupMenu = item.hSubMenu ? generatePopup(item.hSubMenu, popup) : 0; + int res = menuItemEntry(subMenu, i, item, text, icon); + + int lastSep = text.lastIndexOf(QRegExp(QLatin1String("[\\s]"))); + if (lastSep != -1) { + QString keyString = text.right(text.length() - lastSep); + accel = keyString; + if ((int)accel) + text = text.left(lastSep); + } + + if (popupMenu) + popupMenu->setTitle(text); + + switch (res) { + case MFT_STRING: + if (popupMenu) + action = popup->addMenu(popupMenu); + else + action = popup->addAction(text); + break; + case MFT_BITMAP: + if (popupMenu) + action = popup->addMenu(popupMenu); + else + action = popup->addAction(icon, text); + break; + } + + if (action) { + if (int(accel)) + action->setShortcut(accel); + if (!icon.isNull()) + action->setIcon(icon); + } + } + + if (action) { + OleMenuItem oleItem(subMenu, item.wID, popupMenu); + menuItemMap.insert(action, oleItem); + } + } + return popup; +} +#endif + +#if defined(Q_OS_WINCE) +HRESULT WINAPI QAxClientSite::SetMenu(HMENU /*hmenuShared*/, HOLEMENU /*holemenu*/, HWND /*hwndActiveObject*/) +{ + return E_NOTIMPL; +#else +HRESULT WINAPI QAxClientSite::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) +{ + AX_DEBUG(QAxClientSite::SetMenu); + + if (hmenuShared) { + m_menuOwner = hwndActiveObject; + QMenuBar *mb = menuBar; + if (!mb) + mb = widget->window()->findChild<QMenuBar*>(); + if (!mb) + return E_NOTIMPL; + menuBar = mb; + + int count = GetMenuItemCount(hmenuShared); + for (int i = 0; i < count; ++i) { + MENUITEMINFO item; + memset(&item, 0, sizeof(MENUITEMINFO)); + item.cbSize = sizeof(MENUITEMINFO); + item.fMask = MIIM_ID | MIIM_TYPE | MIIM_SUBMENU; + ::GetMenuItemInfo(hmenuShared, i, true, &item); + + QAction *action = 0; + QMenu *popupMenu = 0; + if (item.fType == MFT_SEPARATOR) { + action = menuBar->addSeparator(); + } else { + QString text; + QPixmap icon; + popupMenu = item.hSubMenu ? generatePopup(item.hSubMenu, menuBar) : 0; + int res = menuItemEntry(hmenuShared, i, item, text, icon); + + if (popupMenu) + popupMenu->setTitle(text); + + switch(res) { + case MFT_STRING: + if (popupMenu) + action = menuBar->addMenu(popupMenu); + else + action = menuBar->addAction(text); + break; + case MFT_BITMAP: + if (popupMenu) + action = menuBar->addMenu(popupMenu); + else + action = menuBar->addAction(text); + break; + default: + break; + } + if (action && !icon.isNull()) + action->setIcon(icon); + } + + if (action) { + OleMenuItem oleItem(hmenuShared, item.wID, popupMenu); + menuItemMap.insert(action, oleItem); + } + } + if (count) { + const QMetaObject *mbmo = menuBar->metaObject(); + int index = mbmo->indexOfSignal("triggered(QAction*)"); + Q_ASSERT(index != -1); + menuBar->disconnect(SIGNAL(triggered(QAction*)), host); + QMetaObject::connect(menuBar, index, host, index); + } + } else if (menuBar) { + m_menuOwner = 0; + QMap<QAction*, OleMenuItem>::Iterator it; + for (it = menuItemMap.begin(); it != menuItemMap.end(); ++it) { + QAction *action = it.key(); + delete action; + } + menuItemMap.clear(); + } + + OleSetMenuDescriptor(holemenu, widget ? widget->window()->winId() : 0, m_menuOwner, this, m_spInPlaceActiveObject); + return S_OK; +#endif +} + +#if defined(Q_OS_WINCE) +int QAxClientSite::qt_metacall(QMetaObject::Call /*call*/, int isignal, void ** /*argv*/) +{ + return isignal; +#else +int QAxClientSite::qt_metacall(QMetaObject::Call call, int isignal, void **argv) +{ + if (!m_spOleObject || call != QMetaObject::InvokeMetaMethod || !menuBar) + return isignal; + + if (isignal != menuBar->metaObject()->indexOfSignal("triggered(QAction*)")) + return isignal; + + QAction *action = *(QAction**)argv[1]; + // ### + + OleMenuItem oleItem = menuItemMap.value(action); + if (oleItem.hMenu) + ::PostMessage(m_menuOwner, WM_COMMAND, oleItem.id, 0); + return -1; +#endif +} + + +HRESULT WINAPI QAxClientSite::RemoveMenus(HMENU /*hmenuShared*/) +{ +#if defined(Q_OS_WINCE) + return E_NOTIMPL; +#else + AX_DEBUG(QAxClientSite::RemoveMenus); + QMap<QAction*, OleMenuItem>::Iterator it; + for (it = menuItemMap.begin(); it != menuItemMap.end(); ++it) { + QAction *action = it.key(); + action->setVisible(false); + delete action; + } + menuItemMap.clear(); + return S_OK; +#endif +} + +HRESULT WINAPI QAxClientSite::SetStatusText(LPCOLESTR pszStatusText) +{ + QStatusTipEvent tip(QString::fromWCharArray(pszStatusText)); + QApplication::sendEvent(widget, &tip); + return S_OK; +} + +extern Q_GUI_EXPORT bool qt_win_ignoreNextMouseReleaseEvent; + +HRESULT WINAPI QAxClientSite::EnableModeless(BOOL fEnable) +{ + EnableWindow(host->window()->winId(), fEnable); + + if (!fEnable) { + if (!QApplicationPrivate::isBlockedByModal(host)) + QApplicationPrivate::enterModal(host); + } else { + if (QApplicationPrivate::isBlockedByModal(host)) + QApplicationPrivate::leaveModal(host); + } + qt_win_ignoreNextMouseReleaseEvent = false; + return S_OK; +} + +HRESULT WINAPI QAxClientSite::TranslateAccelerator(LPMSG lpMsg, WORD grfModifiers) +{ + return TranslateAccelerator(lpMsg, (DWORD)grfModifiers); +} + +//**** IOleInPlaceUIWindow +HRESULT WINAPI QAxClientSite::GetBorder(LPRECT lprectBorder) +{ +#ifndef QAX_SUPPORT_BORDERSPACE + Q_UNUSED(lprectBorder); + return INPLACE_E_NOTOOLSPACE; +#else + AX_DEBUG(QAxClientSite::GetBorder); + + QMainWindow *mw = qobject_cast<QMainWindow*>(widget->window()); + if (!mw) + return INPLACE_E_NOTOOLSPACE; + + RECT border = { 0,0, 300, 200 }; + *lprectBorder = border; + return S_OK; +#endif +} + +HRESULT WINAPI QAxClientSite::RequestBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/) +{ +#ifndef QAX_SUPPORT_BORDERSPACE + return INPLACE_E_NOTOOLSPACE; +#else + AX_DEBUG(QAxClientSite::RequestBorderSpace); + + QMainWindow *mw = qobject_cast<QMainWindow*>(widget->window()); + if (!mw) + return INPLACE_E_NOTOOLSPACE; + + return S_OK; +#endif +} + +HRESULT WINAPI QAxClientSite::SetBorderSpace(LPCBORDERWIDTHS pborderwidths) +{ +#ifndef QAX_SUPPORT_BORDERSPACE + Q_UNUSED(pborderwidths); + return OLE_E_INVALIDRECT; +#else + AX_DEBUG(QAxClientSite::SetBorderSpace); + + // object has no toolbars and wants container toolbars to remain + if (!pborderwidths) + return S_OK; + + QMainWindow *mw = qobject_cast<QMainWindow*>(widget->window()); + if (!mw) + return OLE_E_INVALIDRECT; + + bool removeToolBars = !(pborderwidths->left || pborderwidths->top || pborderwidths->right || pborderwidths->bottom); + + // object has toolbars, and wants container to remove toolbars + if (removeToolBars) { + if (mw) { + //### remove our toolbars + } + } + + if (pborderwidths->left) { + QDockWidget *left = new QDockWidget(mw); + left->setFixedWidth(pborderwidths->left); + mw->addDockWidget(Qt::LeftDockWidgetArea, left); + left->show(); + } + if (pborderwidths->top) { + QDockWidget *top = new QDockWidget(mw); + top->setFixedHeight(pborderwidths->top); + mw->addDockWidget(Qt::TopDockWidgetArea, top); + top->show(); + } + + return S_OK; +#endif +} + +HRESULT WINAPI QAxClientSite::SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + AX_DEBUG(QAxClientSite::SetActiveObject); + + Q_UNUSED(pszObjName); + // we are ignoring the name of the object, as suggested by MSDN documentation + // for IOleInPlaceUIWindow::SetActiveObject(). + + if (m_spInPlaceActiveObject) { + if (!inPlaceModelessEnabled) + m_spInPlaceActiveObject->EnableModeless(true); + inPlaceModelessEnabled = true; + m_spInPlaceActiveObject->Release(); + } + + m_spInPlaceActiveObject = pActiveObject; + if (m_spInPlaceActiveObject) + m_spInPlaceActiveObject->AddRef(); + + return S_OK; +} + +//**** IOleDocumentSite +HRESULT WINAPI QAxClientSite::ActivateMe(IOleDocumentView *pViewToActivate) +{ + AX_DEBUG(QAxClientSite::ActivateMe); + + if (m_spActiveView) + m_spActiveView->Release(); + m_spActiveView = 0; + + if (!pViewToActivate) { + IOleDocument *document = 0; + m_spOleObject->QueryInterface(IID_IOleDocument, (void**)&document); + if (!document) + return E_FAIL; + + document->CreateView(this, 0, 0, &pViewToActivate); + + document->Release(); + if (!pViewToActivate) + return E_OUTOFMEMORY; + } else { + pViewToActivate->SetInPlaceSite(this); + } + + m_spActiveView = pViewToActivate; + m_spActiveView->AddRef(); + + m_spActiveView->UIActivate(TRUE); + + RECT rect; + GetClientRect(widget->winId(), &rect); + m_spActiveView->SetRect(&rect); + m_spActiveView->Show(TRUE); + + return S_OK; +} + +QSize QAxClientSite::minimumSizeHint() const +{ + if (!m_spOleObject) + return QSize(); + + SIZE sz = { 0, 0 }; + m_spOleObject->SetExtent(DVASPECT_CONTENT, &sz); + HRESULT res = m_spOleObject->GetExtent(DVASPECT_CONTENT, &sz); + if (SUCCEEDED(res)) { + return QSize(MAP_LOGHIM_TO_PIX(sz.cx, widget->logicalDpiX()), + MAP_LOGHIM_TO_PIX(sz.cy, widget->logicalDpiY())); + } + return QSize(); +} + +void QAxClientSite::windowActivationChange() +{ + AX_DEBUG(QAxClientSite::windowActivationChange); + + if (m_spInPlaceActiveObject && widget) { + QWidget *modal = QApplication::activeModalWidget(); + if (modal && inPlaceModelessEnabled) { + m_spInPlaceActiveObject->EnableModeless(false); + inPlaceModelessEnabled = false; + } else if (!inPlaceModelessEnabled) { + m_spInPlaceActiveObject->EnableModeless(true); + inPlaceModelessEnabled = true; + } + m_spInPlaceActiveObject->OnFrameWindowActivate(widget->isActiveWindow()); + } +} + + +//**** QWidget + +QAxHostWidget::QAxHostWidget(QWidget *parent, QAxClientSite *ax) +: QWidget(parent), setFocusTimer(0), hasFocus(false), axhost(ax) +{ + setAttribute(Qt::WA_NoBackground); + setAttribute(Qt::WA_NoSystemBackground); + setAttribute(Qt::WA_OpaquePaintEvent); + setAttribute(Qt::WA_PaintOnScreen); + + setObjectName(parent->objectName() + QLatin1String(" - QAxHostWidget")); +} + +QAxHostWidget::~QAxHostWidget() +{ + if (axhost) + axhost->reset(this); +} + +int QAxHostWidget::qt_metacall(QMetaObject::Call call, int isignal, void **argv) +{ + if (axhost) + return axhost->qt_metacall(call, isignal, argv); + return -1; +} + +void* QAxHostWidget::qt_metacast(const char *clname) +{ + if (!clname) return 0; + if (!qstrcmp(clname,"QAxHostWidget")) + return static_cast<void*>(const_cast< QAxHostWidget*>(this)); + return QWidget::qt_metacast(clname); +} + +QSize QAxHostWidget::sizeHint() const +{ + return axhost ? axhost->sizeHint() : QWidget::sizeHint(); +} + +QSize QAxHostWidget::minimumSizeHint() const +{ + QSize size; + if (axhost) + size = axhost->minimumSizeHint(); + if (size.isValid()) + return size; + return QWidget::minimumSizeHint(); +} + +void QAxHostWidget::resizeObject() +{ + if (!axhost) + return; + + // document server - talk to view? + if (axhost->m_spActiveView) { + RECT rect; + GetClientRect(winId(), &rect); + axhost->m_spActiveView->SetRect(&rect); + + return; + } + + SIZEL hmSize; + hmSize.cx = MAP_PIX_TO_LOGHIM(width(), logicalDpiX()); + hmSize.cy = MAP_PIX_TO_LOGHIM(height(), logicalDpiY()); + + if (axhost->m_spOleObject) + axhost->m_spOleObject->SetExtent(DVASPECT_CONTENT, &hmSize); + if (axhost->m_spInPlaceObject) { + RECT rcPos = { x(), y(), x()+width(), y()+height() }; + axhost->m_spInPlaceObject->SetObjectRects(&rcPos, &rcPos); + } +} + +void QAxHostWidget::resizeEvent(QResizeEvent *) +{ + resizeObject(); +} + +void QAxHostWidget::showEvent(QShowEvent *) +{ + resizeObject(); +} + +bool QAxHostWidget::winEvent(MSG *msg, long *result) +{ + if (axhost && axhost->inPlaceObjectWindowless) { + Q_ASSERT(axhost->m_spInPlaceObject); + IOleInPlaceObjectWindowless *windowless = (IOleInPlaceObjectWindowless*)axhost->m_spInPlaceObject; + Q_ASSERT(windowless); + LRESULT lres; + HRESULT hres = windowless->OnWindowMessage(msg->message, msg->wParam, msg->lParam, &lres); + if (hres == S_OK) + return true; + } + return QWidget::winEvent(msg, result); +} + +bool QAxHostWidget::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::Timer: + if (axhost && ((QTimerEvent*)e)->timerId() == setFocusTimer) { + killTimer(setFocusTimer); + setFocusTimer = 0; + RECT rcPos = { x(), y(), x()+size().width(), y()+size().height() }; + axhost->m_spOleObject->DoVerb(OLEIVERB_UIACTIVATE, 0, (IOleClientSite*)axhost, 0, winId(), &rcPos); + if (axhost->m_spActiveView) + axhost->m_spActiveView->UIActivate(TRUE); + } + break; + case QEvent::WindowBlocked: + if (IsWindowEnabled(winId())) { + EnableWindow(winId(), false); + if (axhost && axhost->m_spInPlaceActiveObject) { + axhost->inPlaceModelessEnabled = false; + axhost->m_spInPlaceActiveObject->EnableModeless(false); + } + } + break; + case QEvent::WindowUnblocked: + if (!IsWindowEnabled(winId())) { + EnableWindow(winId(), true); + if (axhost && axhost->m_spInPlaceActiveObject) { + axhost->inPlaceModelessEnabled = true; + axhost->m_spInPlaceActiveObject->EnableModeless(true); + } + } + break; + default: + break; + } + + return QWidget::event(e); +} + +bool QAxHostWidget::eventFilter(QObject *o, QEvent *e) +{ + // focus goes to Qt while ActiveX still has it - deactivate + QWidget *newFocus = qobject_cast<QWidget*>(o); + if (e->type() == QEvent::FocusIn && hasFocus + && newFocus && newFocus->window() == window()) { + if (axhost && axhost->m_spInPlaceActiveObject && axhost->m_spInPlaceObject) + axhost->m_spInPlaceObject->UIDeactivate(); + qApp->removeEventFilter(this); + } + + return QWidget::eventFilter(o, e); +} + +void QAxHostWidget::focusInEvent(QFocusEvent *e) +{ + QWidget::focusInEvent(e); + + if (!axhost || !axhost->m_spOleObject) + return; + + // this is called by QWidget::setFocus which calls ::SetFocus on "this", + // so we have to UIActivate the control after all that had happend. + AX_DEBUG(Setting focus on in-place object); + setFocusTimer = startTimer(0); +} + +void QAxHostWidget::focusOutEvent(QFocusEvent *e) +{ + QWidget::focusOutEvent(e); + if (setFocusTimer) { + killTimer(setFocusTimer); + setFocusTimer = 0; + } + if (e->reason() == Qt::PopupFocusReason || e->reason() == Qt::MenuBarFocusReason) + return; + + if (!axhost || !axhost->m_spInPlaceActiveObject || !axhost->m_spInPlaceObject) + return; + + AX_DEBUG(Deactivating in-place object); + axhost->m_spInPlaceObject->UIDeactivate(); +} + + +void QAxHostWidget::paintEvent(QPaintEvent*) +{ + if (!QPainter::redirected(this)) + return; + + IViewObject *view = 0; + if (axhost) + axhost->widget->queryInterface(IID_IViewObject, (void**)&view); + if (!view) + return; + + // somebody tries to grab us! + QPixmap pm(size()); + pm.fill(); + + HBITMAP hBmp = pm.toWinHBITMAP(); + HDC hBmp_hdc = CreateCompatibleDC(qt_win_display_dc()); + HGDIOBJ old_hBmp = SelectObject(hBmp_hdc, hBmp); + + RECTL bounds; + bounds.left = 0; + bounds.right = pm.width(); + bounds.top = 0; + bounds.bottom = pm.height(); + + view->Draw(DVASPECT_CONTENT, -1, 0, 0, 0, hBmp_hdc, &bounds, 0, 0 /*fptr*/, 0); + view->Release(); + + QPainter painter(this); + painter.drawPixmap(0, 0, QPixmap::fromWinHBITMAP(hBmp)); + + SelectObject(hBmp_hdc, old_hBmp); + DeleteObject(hBmp); + DeleteDC(hBmp_hdc); +} + +/*! + \class QAxWidget + \brief The QAxWidget class is a QWidget that wraps an ActiveX control. + + \inmodule QAxContainer + + A QAxWidget can be instantiated as an empty object, with the name + of the ActiveX control it should wrap, or with an existing + interface pointer to the ActiveX control. The ActiveX control's + properties, methods and events which only use QAxBase + supported data types, become available as Qt properties, + slots and signals. The base class QAxBase provides an API to + access the ActiveX directly through the \c IUnknown pointer. + + QAxWidget is a QWidget and can mostly be used as such, e.g. it can be + organized in a widget hierarchy and layouts or act as an event filter. + Standard widget properties, e.g. \link QWidget::enabled + enabled \endlink are supported, but it depends on the ActiveX + control to implement support for ambient properties like e.g. + palette or font. QAxWidget tries to provide the necessary hints. + + However, you cannot reimplement Qt-specific event handlers like + mousePressEvent or keyPressEvent and expect them to be called reliably. + The embedded control covers the QAxWidget completely, and usually + handles the user interface itself. Use control-specific APIs (i.e. listen + to the signals of the control), or use standard COM techniques like + window procedure subclassing. + + QAxWidget also inherits most of its ActiveX-related functionality + from QAxBase, notably dynamicCall() and querySubObject(). + + \warning + You can subclass QAxWidget, but you cannot use the \c Q_OBJECT macro + in the subclass (the generated moc-file will not compile), so you + cannot add further signals, slots or properties. This limitation + is due to the metaobject information generated in runtime. To work + around this problem, aggregate the QAxWidget as a member of the + QObject subclass. + + \sa QAxBase, QAxObject, QAxScript, {ActiveQt Framework} +*/ + +/*! + Creates an empty QAxWidget widget and propagates \a parent + and \a f to the QWidget constructor. To initialize a control, + call setControl(). +*/ +QAxWidget::QAxWidget(QWidget *parent, Qt::WindowFlags f) +: QWidget(parent, f), container(0) +{ +} + +/*! + Creates an QAxWidget widget and initializes the ActiveX control \a c. + \a parent and \a f are propagated to the QWidget contructor. + + \sa setControl() +*/ +QAxWidget::QAxWidget(const QString &c, QWidget *parent, Qt::WindowFlags f) +: QWidget(parent, f), container(0) +{ + setControl(c); +} + +/*! + Creates a QAxWidget that wraps the COM object referenced by \a iface. + \a parent and \a f are propagated to the QWidget contructor. +*/ +QAxWidget::QAxWidget(IUnknown *iface, QWidget *parent, Qt::WindowFlags f) +: QWidget(parent, f), QAxBase(iface), container(0) +{ +} + +/*! + Shuts down the ActiveX control and destroys the QAxWidget widget, + cleaning up all allocated resources. + + \sa clear() +*/ +QAxWidget::~QAxWidget() +{ + if (container) + container->reset(this); + clear(); +} + +/*! + \since 4.2 + + Calls QAxBase::initialize(\a ptr), and embeds the control in this + widget by calling createHostWindow(false) if successful. + + To initialize the control before it is activated, reimplement this + function and add your initialization code before you call + createHostWindow(true). +*/ +bool QAxWidget::initialize(IUnknown **ptr) +{ + if (!QAxBase::initialize(ptr)) + return false; + + return createHostWindow(false); // assume that control is not initialized +} + +/*! + Creates the client site for the ActiveX control, and returns true if + the control could be embedded successfully, otherwise returns false. + If \a initialized is true the control has already been initialized. + + This function is called by initialize(). If you reimplement initialize + to customize the actual control instantiation, call this function in your + reimplementation to have the control embedded by the default client side. + Creates the client site for the ActiveX control, and returns true if + the control could be embedded successfully, otherwise returns false. +*/ +bool QAxWidget::createHostWindow(bool initialized) +{ + return createHostWindow(initialized, QByteArray()); +} + +/*! + \since 4.4 + + Creates the client site for the ActiveX control, and returns true if + the control could be embedded successfully, otherwise returns false. + If \a initialized is false the control will be initialized using the + \a data. The control will be initialized through either IPersistStreamInit + or IPersistStorage interface. + + If the control needs to be initialized using custom data, call this function + in your reimplementation of initialize(). This function is not called by + the default implementation of initialize(). +*/ +bool QAxWidget::createHostWindow(bool initialized, const QByteArray &data) +{ +#ifdef QT3_SUPPORT + QApplication::sendPostedEvents(0, QEvent::ChildInserted); +#endif + + container = new QAxClientSite(this); + container->activateObject(initialized, data); + +#if !defined(Q_OS_WINCE) + ATOM filter_ref = FindAtom(qaxatom); +#endif + if (!filter_ref) + previous_filter = QAbstractEventDispatcher::instance()->setEventFilter(axc_FilterProc); +#if !defined(Q_OS_WINCE) + AddAtom(qaxatom); +#else + ++filter_ref; +#endif + + if (parentWidget()) + QApplication::postEvent(parentWidget(), new QEvent(QEvent::LayoutRequest)); + + return true; +} + +/*! + Reimplement this function when you want to implement additional + COM interfaces for the client site of the ActiveX control, or when + you want to provide alternative implementations of COM interfaces. + Return a new object of a QAxAggregated subclass. + + The default implementation returns the null pointer. +*/ +QAxAggregated *QAxWidget::createAggregate() +{ + return 0; +} + +/*! + \reimp + + Shuts down the ActiveX control. +*/ +void QAxWidget::clear() +{ + if (isNull()) + return; + if (!control().isEmpty()) { +#if !defined(Q_OS_WINCE) + ATOM filter_ref = FindAtom(qaxatom); + if (filter_ref) + DeleteAtom(filter_ref); + filter_ref = FindAtom(qaxatom); + if (!filter_ref) { +#else + if (!filter_ref && !--filter_ref) { +#endif + QAbstractEventDispatcher::instance()->setEventFilter(previous_filter); + previous_filter = 0; + } + } + + if (container) + container->deactivate(); + + QAxBase::clear(); + setFocusPolicy(Qt::NoFocus); + + if (container) { + container->releaseAll(); + container->Release(); + } + container = 0; +} + +/*! + \since 4.1 + + Requests the ActiveX control to perform the action \a verb. The + possible verbs are returned by verbs(). + + The function returns true if the object could perform the action, otherwise returns false. +*/ +bool QAxWidget::doVerb(const QString &verb) +{ + if (!verbs().contains(verb)) + return false; + + HRESULT hres = container->doVerb(indexOfVerb(verb)); + + return hres == S_OK; +} + + /*! + \fn QObject *QAxWidget::qObject() const + \internal +*/ + +/*! + \internal +*/ +const QMetaObject *QAxWidget::metaObject() const +{ + return QAxBase::metaObject(); +} + +/*! + \internal +*/ +const QMetaObject *QAxWidget::parentMetaObject() const +{ + return &QWidget::staticMetaObject; +} + +/*! + \internal +*/ +void *QAxWidget::qt_metacast(const char *cname) +{ + if (!qstrcmp(cname, "QAxWidget")) return (void*)this; + if (!qstrcmp(cname, "QAxBase")) return (QAxBase*)this; + return QWidget::qt_metacast(cname); +} + +/*! + \internal +*/ +const char *QAxWidget::className() const +{ + return "QAxWidget"; +} + +/*! + \internal +*/ +int QAxWidget::qt_metacall(QMetaObject::Call call, int id, void **v) +{ + id = QWidget::qt_metacall(call, id, v); + if (id < 0) + return id; + return QAxBase::qt_metacall(call, id, v); +} + +/*! + \reimp +*/ +QSize QAxWidget::sizeHint() const +{ + if (container) { + QSize sh = container->sizeHint(); + if (sh.isValid()) + return sh; + } + + return QWidget::sizeHint(); +} + +/*! + \reimp +*/ +QSize QAxWidget::minimumSizeHint() const +{ + if (container) { + QSize sh = container->minimumSizeHint(); + if (sh.isValid()) + return sh; + } + + return QWidget::minimumSizeHint(); +} + +/*! + \reimp +*/ +void QAxWidget::changeEvent(QEvent *e) +{ + if (isNull()) + return; + + switch (e->type()) { + case QEvent::EnabledChange: + container->emitAmbientPropertyChange(DISPID_AMBIENT_UIDEAD); + break; + case QEvent::FontChange: + container->emitAmbientPropertyChange(DISPID_AMBIENT_FONT); + break; + case QEvent::PaletteChange: + container->emitAmbientPropertyChange(DISPID_AMBIENT_BACKCOLOR); + container->emitAmbientPropertyChange(DISPID_AMBIENT_FORECOLOR); + break; + case QEvent::ActivationChange: + container->windowActivationChange(); + break; + default: + break; + } +} + +/*! + \reimp +*/ +void QAxWidget::resizeEvent(QResizeEvent *) +{ + if (container) + container->resize(size()); +} + +/*! + \reimp +*/ +void QAxWidget::connectNotify(const char *) +{ + QAxBase::connectNotify(); +} + + +/*! + Reimplement this function to pass certain key events to the + ActiveX control. \a message is the Window message identifier + specifying the message type (ie. WM_KEYDOWN), and \a keycode is + the virtual keycode (ie. VK_TAB). + + If the function returns true the key event is passed on to the + ActiveX control, which then either processes the event or passes + the event on to Qt. + + If the function returns false the processing of the key event is + ignored by ActiveQt, ie. the ActiveX control might handle it or + not. + + The default implementation returns true for the following cases: + + \table + \header + \i WM_SYSKEYDOWN + \i WM_SYSKEYUP + \i WM_KEYDOWN + \row + \i All keycodes + \i VK_MENU + \i VK_TAB, VK_DELETE and all non-arrow-keys in combination with VK_SHIFT, + VK_CONTROL or VK_MENU + \endtable + + This table is the result of experimenting with popular ActiveX controls, + ie. Internet Explorer and Microsoft Office applications, but for some + controls it might require modification. +*/ +bool QAxWidget::translateKeyEvent(int message, int keycode) const +{ + bool translate = false; + + switch (message) { + case WM_SYSKEYDOWN: + translate = true; + break; + case WM_KEYDOWN: + translate = keycode == VK_TAB + || keycode == VK_DELETE; + if (!translate) { + int state = 0; + if (GetKeyState(VK_SHIFT) < 0) + state |= 0x01; + if (GetKeyState(VK_CONTROL) < 0) + state |= 0x02; + if (GetKeyState(VK_MENU) < 0) + state |= 0x04; + if (state) { + state = keycode < VK_LEFT || keycode > VK_DOWN; + } + translate = state; + } + break; + case WM_SYSKEYUP: + translate = keycode == VK_MENU; + break; + } + + return translate; +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/container/qaxwidget.h b/src/activeqt/container/qaxwidget.h new file mode 100644 index 0000000..58069a1 --- /dev/null +++ b/src/activeqt/container/qaxwidget.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXWIDGET_H +#define QAXWIDGET_H + +#include <ActiveQt/qaxbase.h> +#include <QtGui/qwidget.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +class QAxHostWindow; +class QAxAggregated; + +class QAxClientSite; + +class QAxWidget : public QWidget, public QAxBase +{ +public: + const QMetaObject *metaObject() const; + void* qt_metacast(const char*); + int qt_metacall(QMetaObject::Call, int, void **); + QObject* qObject() const { return (QWidget*)this; } + const char *className() const; + + QAxWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); + QAxWidget(const QString &c, QWidget *parent = 0, Qt::WindowFlags f = 0); + QAxWidget(IUnknown *iface, QWidget *parent = 0, Qt::WindowFlags f = 0); + ~QAxWidget(); + + void clear(); + bool doVerb(const QString &verb); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + virtual QAxAggregated *createAggregate(); + +protected: + bool initialize(IUnknown**); + virtual bool createHostWindow(bool); + bool createHostWindow(bool, const QByteArray&); + + void changeEvent(QEvent *e); + void resizeEvent(QResizeEvent *); + + virtual bool translateKeyEvent(int message, int keycode) const; + + void connectNotify(const char *signal); +private: + friend class QAxClientSite; + QAxClientSite *container; + + const QMetaObject *parentMetaObject() const; + static QMetaObject staticMetaObject; +}; + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +template <> inline QAxWidget *qobject_cast_helper<QAxWidget*>(const QObject *o, QAxWidget *) +#else +template <> inline QAxWidget *qobject_cast<QAxWidget*>(const QObject *o) +#endif +{ + void *result = o ? const_cast<QObject *>(o)->qt_metacast("QAxWidget") : 0; + return (QAxWidget*)(result); +} + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +template <> inline QAxWidget *qobject_cast_helper<QAxWidget*>(QObject *o, QAxWidget *) +#else +template <> inline QAxWidget *qobject_cast<QAxWidget*>(QObject *o) +#endif +{ + void *result = o ? o->qt_metacast("QAxWidget") : 0; + return (QAxWidget*)(result); +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXWIDGET_H diff --git a/src/activeqt/control/control.pro b/src/activeqt/control/control.pro new file mode 100644 index 0000000..361ca29 --- /dev/null +++ b/src/activeqt/control/control.pro @@ -0,0 +1,39 @@ +TEMPLATE = lib + +TARGET = ActiveQt +CONFIG += qt_install_headers +SYNCQT.HEADER_FILES = qaxaggregated.h qaxbindable.h qaxfactory.h +SYNCQT.HEADER_CLASSES = ../../../include/ActiveQt/QAxAggregated ../../../include/ActiveQt/QAxBindable ../../../include/ActiveQt/QAxFactory ../../../include/ActiveQt/QAxClass +include(../../qt_install.pri) + +TARGET = QAxServer + +!debug_and_release|build_pass { + CONFIG(debug, debug|release) { + TARGET = $$member(TARGET, 0)d + } +} + +CONFIG += qt warn_off staticlib +QTDIR_build:DESTDIR = $$QT_BUILD_TREE\\lib + +DEFINES += QAX_SERVER +win32-g++*:DEFINES += QT_NEEDS_QMAIN +win32-borland:DEFINES += QT_NEEDS_QMAIN + +LIBS += -luser32 -lole32 -loleaut32 -lgdi32 +win32-g++*:LIBS += -luuid + +HEADERS = qaxaggregated.h \ + qaxbindable.h \ + qaxfactory.h \ + ../shared/qaxtypes.h + +SOURCES = qaxserver.cpp \ + qaxserverbase.cpp \ + qaxbindable.cpp \ + qaxfactory.cpp \ + qaxservermain.cpp \ + qaxserverdll.cpp \ + qaxmain.cpp \ + ../shared/qaxtypes.cpp diff --git a/src/activeqt/control/qaxaggregated.h b/src/activeqt/control/qaxaggregated.h new file mode 100644 index 0000000..f8537c8 --- /dev/null +++ b/src/activeqt/control/qaxaggregated.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXAGGREGATED_H +#define QAXAGGREGATED_H + +#include <QtCore/qobject.h> + +struct IUnknown; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +struct QUuid; + +class QAxAggregated +{ + friend class QAxServerBase; + friend class QAxClientSite; +public: + virtual long queryInterface(const QUuid &iid, void **iface) = 0; + +protected: + virtual ~QAxAggregated() + {} + + inline IUnknown *controllingUnknown() const + { return controlling_unknown; } + inline QWidget *widget() const + { + return qobject_cast<QWidget*>(the_object); + } + inline QObject *object() const { return the_object; } + +private: + IUnknown *controlling_unknown; + QObject *the_object; +}; + +#define QAXAGG_IUNKNOWN \ + HRESULT WINAPI QueryInterface(REFIID iid, LPVOID *iface) { \ + return controllingUnknown()->QueryInterface(iid, iface); } \ + ULONG WINAPI AddRef() {return controllingUnknown()->AddRef(); } \ + ULONG WINAPI Release() {return controllingUnknown()->Release(); } \ + +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QAXAGGREGATED_H diff --git a/src/activeqt/control/qaxbindable.cpp b/src/activeqt/control/qaxbindable.cpp new file mode 100644 index 0000000..f023a19 --- /dev/null +++ b/src/activeqt/control/qaxbindable.cpp @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxbindable.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qmetaobject.h> + +#include <qt_windows.h> // for IUnknown +#include "../shared/qaxtypes.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QAxBindable + \brief The QAxBindable class provides an interface between a + QWidget and an ActiveX client. + + \inmodule QAxServer + + The functions provided by this class allow an ActiveX control to + communicate property changes to a client application. Inherit + your control class from both QWidget (directly or indirectly) and + this class to get access to this class's functions. The + \l{moc}{meta-object compiler} requires you to inherit from + QWidget first. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 0 + + When implementing the property write function, use + requestPropertyChange() to get permission from the ActiveX client + application to change this property. When the property changes, + call propertyChanged() to notify the ActiveX client application + about the change. If a fatal error occurs in the control, use the + static reportError() function to notify the client. + + Use the interface returned by clientSite() to call the ActiveX + client. To implement additional COM interfaces in your ActiveX + control, reimplement createAggregate() to return a new object of a + QAxAggregated subclass. + + The ActiveQt \l{activeqt/opengl}{OpenGL} example shows how to use + QAxBindable to implement additional COM interfaces. + + \sa QAxAggregated, QAxFactory, {ActiveQt Framework} +*/ + +/*! + Constructs an empty QAxBindable object. +*/ +QAxBindable::QAxBindable() +:activex(0) +{ +} + +/*! + Destroys the QAxBindable object. +*/ +QAxBindable::~QAxBindable() +{ +} + +/*! + Call this function to request permission to change the property + \a property from the client that is hosting this ActiveX control. + Returns true if the client allows the change; otherwise returns + false. + + This function is usually called first in the write function for \a + property, and writing is abandoned if the function returns false. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 1 + + \sa propertyChanged() +*/ +bool QAxBindable::requestPropertyChange(const char *property) +{ + if (!activex) + return true; + + return activex->emitRequestPropertyChange(property); +} + +/*! + Call this function to notify the client that is hosting this + ActiveX control that the property \a property has been changed. + + This function is usually called at the end of the property's write + function. + + \sa requestPropertyChange() +*/ +void QAxBindable::propertyChanged(const char *property) +{ + if (!activex) + return; + + activex->emitPropertyChanged(property); +} + +/*! + Returns a pointer to the client site interface for this ActiveX object, + or null if no client site has been set. + + Call \c QueryInterface() on the returned interface to get the + interface you want to call. +*/ +IUnknown *QAxBindable::clientSite() const +{ + if (!activex) + return 0; + + return activex->clientSite(); +} + +/*! + Reimplement this function when you want to implement additional + COM interfaces in the ActiveX control, or when you want to provide + alternative implementations of COM interfaces. Return a new object + of a QAxAggregated subclass. + + The default implementation returns the null pointer. +*/ +QAxAggregated *QAxBindable::createAggregate() +{ + return 0; +} + +/*! + Reports an error to the client application. \a code is a + control-defined error code. \a desc is a human-readable description + of the error intended for the application user. \a src is the name + of the source for the error, typically the ActiveX server name. \a + context can be the location of a help file with more information + about the error. If \a context ends with a number in brackets, + e.g. [12], this number will be interpreted as the context ID in + the help file. +*/ +void QAxBindable::reportError(int code, const QString &src, const QString &desc, const QString &context) +{ + if (!activex) + return; + + activex->reportError(code, src, desc, context); +} + +/*! + \since 4.1 + + If the COM object supports a MIME type then this function is called + to initialize the COM object from the data \a source in \a format. + You have to open \a source for reading before you can read from it. + + Returns true to indicate success. If the function returns false, + then ActiveQt will process the data by setting the properties + through the meta object system. + + If you reimplement this function you also have to implement + writeData(). The default implementation does nothing and returns + false. + + \warning ActiveX controls embedded in HTML can use either the + \c type and \c data attribute of the \c object tag to read data, + or use a list of \c param tags to initialize properties. If + \c param tags are used, then Internet Explorer will ignore the + \c data attribute, and readData will not be called. + + \sa writeData() +*/ +bool QAxBindable::readData(QIODevice *source, const QString &format) +{ + Q_UNUSED(source); + Q_UNUSED(format); + return false; +} + +/*! + \since 4.1 + + If the COM object supports a MIME type then this function is called + to store the COM object into \a sink. + You have to open \a sink for writing before you can write to it. + + Returns true to indicate success. If the function returns false, + then ActiveQt will serialize the object by storing the property + values. + + If you reimplement this function you also have to implement + readData(). The default implementation does nothing and returns + false. + + \sa readData() +*/ +bool QAxBindable::writeData(QIODevice *sink) +{ + Q_UNUSED(sink); + return false; +} + +/*! + \class QAxAggregated + \brief The QAxAggregated class is an abstract base class for implementations of + additional COM interfaces. + + \inmodule QAxServer + + Create a subclass of QAxAggregated and reimplement + queryInterface() to support additional COM interfaces. Use + multiple inheritance from those COM interfaces. Implement the + IUnknown interface of those COM interfaces by delegating the + calls to \c QueryInterface(), \c AddRef() and \c Release() to the + interface provided by controllingUnknown(). + + Use the widget() method if you need to make calls to the QWidget + implementing the ActiveX control. You must not store that pointer + in your subclass (unless you use QPointer), as the QWidget can + be destroyed by the ActiveQt framework at any time. + + \sa QAxBindable, QAxFactory, {Qt's ActiveX Framework (ActiveQt)} +*/ + +/*! + \fn QAxAggregated::~QAxAggregated() + + The destructor is called internally by Qt. +*/ + +/*! + \fn long QAxAggregated::queryInterface(const QUuid &iid, void **iface) + + Reimplement this pure virtual function to support additional COM + interfaces. Set the value of \a iface to point to this object to + support the interface \a iid. Note that you must cast the \c + this pointer to the appropriate superclass. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 2 + + Return the standard COM results \c S_OK (interface is supported) + or \c E_NOINTERFACE (requested interface is not supported). + + \warning + Even though you must implement the \c IUnknown interface if you + implement any COM interface you must not support the \c IUnknown + interface in your queryInterface() implementation. +*/ + +/*! + \fn IUnknown *QAxAggregated::controllingUnknown() const + + Returns the \c IUnknown interface of the ActiveX control. Implement + the \c IUnknown interface in your QAxAggregated subclass to + delegate calls to \c QueryInterface(), \c AddRef(), and \c + Release() to the interface provided by this function. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 3 + + Instead of declaring and implementing these three functions + manually, you can use the \c QAXAGG_IUNKNOWN macro in the class + declaration of your subclass. +*/ + +/*! + \fn QObject *QAxAggregated::object() const + + Returns a pointer to the QObject subclass implementing the COM object. + This function might return 0. + + \warning + You must not store the returned pointer, unless you use a + QPointer, since the QObject can be destroyed by ActiveQt at any + time. +*/ + +/*! + \fn QWidget *QAxAggregated::widget() const + + Returns a pointer to the QWidget subclass implementing the ActiveX control. + This function might return 0. + + \warning + You must not store the returned pointer, unless you use a + QPointer, since the QWidget can be destroyed by ActiveQt at any + time. +*/ + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/control/qaxbindable.h b/src/activeqt/control/qaxbindable.h new file mode 100644 index 0000000..1e1a6dd --- /dev/null +++ b/src/activeqt/control/qaxbindable.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXBINDABLE_H +#define QAXBINDABLE_H + +#include <QtGui/qwidget.h> + +struct IUnknown; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +class QAxAggregated; +class QIODevice; +struct IAxServerBase; + +class QAxBindable +{ + friend class QAxServerBase; +public: + QAxBindable(); + virtual ~QAxBindable(); + + virtual QAxAggregated *createAggregate(); + void reportError(int code, const QString &src, const QString &desc, const QString &help = QString()); + + virtual bool readData(QIODevice *source, const QString &format); + virtual bool writeData(QIODevice *sink); + +protected: + bool requestPropertyChange(const char *property); + void propertyChanged(const char *property); + + IUnknown *clientSite() const; + +private: + IAxServerBase *activex; +}; + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXBINDABLE_H diff --git a/src/activeqt/control/qaxfactory.cpp b/src/activeqt/control/qaxfactory.cpp new file mode 100644 index 0000000..7a7a285 --- /dev/null +++ b/src/activeqt/control/qaxfactory.cpp @@ -0,0 +1,592 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxfactory.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qfile.h> +#include <qfileinfo.h> +#include <qmetaobject.h> +#include <qsettings.h> +#include <qwidget.h> +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +extern wchar_t qAxModuleFilename[MAX_PATH]; + +/*! + \class QAxFactory + \brief The QAxFactory class defines a factory for the creation of COM components. + + \inmodule QAxServer + + Implement this factory once in your COM server to provide information + about the components the server can create. Subclass QAxFactory and implement + the pure virtual functions in any implementation file (e.g. main.cpp), and export + the factory using the \c QAXFACTORY_EXPORT() macro. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 0 + + If you use the \c Q_CLASSINFO() macro to provide the unique + identifiers or other attributes for your class you can use the \c + QAXFACTORY_BEGIN(), \c QAXCLASS() and \c QAXFACTORY_END() macros to + expose one or more classes as COM objects. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 1 + + + If your server supports just a single COM object, you can use + a default factory implementation through the \c QAXFACTORY_DEFAULT() macro. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 2 + + Only one QAxFactory implementation may be instantiated and + exported by an ActiveX server application. This instance is accessible + through the global qAxFactory() function. + + A factory can also reimplement the registerClass() and + unregisterClass() functions to set additional flags for an ActiveX + control in the registry. To limit the number of methods or + properties a widget class exposes from its parent classes + reimplement exposeToSuperClass(). + + \sa QAxAggregated, QAxBindable, {ActiveQt Framework} +*/ + +/*! + Constructs a QAxFactory object that returns \a libid and \a appid + in the implementation of the respective interface functions. +*/ + +QAxFactory::QAxFactory(const QUuid &libid, const QUuid &appid) +: typelib(libid), app(appid) +{ +} + +/*! + Destroys the QAxFactory object. +*/ +QAxFactory::~QAxFactory() +{ +} + +/*! + \fn QUuid QAxFactory::typeLibID() const + + Reimplement this function to return the ActiveX server's type + library identifier. +*/ +QUuid QAxFactory::typeLibID() const +{ + return typelib; +} + +/*! + \fn QUuid QAxFactory::appID() const + + Reimplement this function to return the ActiveX server's + application identifier. +*/ +QUuid QAxFactory::appID() const +{ + return app; +} + +/*! + \fn QStringList QAxFactory::featureList() const + + Reimplement this function to return a list of the widgets (class + names) supported by this factory. +*/ + +/*! + \fn QObject *QAxFactory::createObject(const QString &key) + + Reimplement this function to return a new object for \a key, or 0 if + this factory doesn't support the value of \a key. + + If the object returned is a QWidget it will be exposed as an ActiveX + control, otherwise the returned object will be exposed as a simple COM + object. +*/ + +/*! + \fn const QMetaObject *QAxFactory::metaObject(const QString &key) const + + Reimplement this function to return the QMetaObject corresponding to + \a key, or 0 if this factory doesn't support the value of \a key. +*/ + +/*! + \fn bool QAxFactory::createObjectWrapper(QObject *object, IDispatch **wrapper) + + Reimplement this function to provide the COM object for \a object + in \a wrapper. Return true if the function was successful; otherwise + return false. + + The default implementation creates a generic automation wrapper based + on the meta object information of \a object. +*/ +// implementation in qaxserverbase.cpp + +/*! + Reimplement this function to return the class identifier for each + \a key returned by the featureList() implementation, or an empty + QUuid if this factory doesn't support the value of \a key. + + The default implementation interprets \a key as the class name, + and returns the value of the Q_CLASSINFO() entry "ClassID". +*/ +QUuid QAxFactory::classID(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QUuid(); + QString id = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("ClassID")).value()); + + return QUuid(id); +} + +/*! + Reimplement this function to return the interface identifier for + each \a key returned by the featureList() implementation, or an + empty QUuid if this factory doesn't support the value of \a key. + + The default implementation interprets \a key as the class name, + and returns the value of the Q_CLASSINFO() entry "InterfaceID". +*/ +QUuid QAxFactory::interfaceID(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QUuid(); + QString id = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("InterfaceID")).value()); + + return QUuid(id); +} + +/*! + Reimplement this function to return the identifier of the event + interface for each \a key returned by the featureList() + implementation, or an empty QUuid if this factory doesn't support + the value of \a key. + + The default implementation interprets \a key as the class name, + and returns the value of the Q_CLASSINFO() entry "EventsID". +*/ +QUuid QAxFactory::eventsID(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QUuid(); + QString id = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("EventsID")).value()); + + return QUuid(id); +} + +/*! + Registers additional values for the class \a key in the system + registry using the \a settings object. The standard values have + already been registered by the framework, but additional values, + e.g. implemented categories, can be added in an implementation of + this function. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 3 + + If you reimplement this function you must also reimplement + unregisterClass() to remove the additional registry values. + + \sa QSettings +*/ +void QAxFactory::registerClass(const QString &key, QSettings *settings) const +{ + Q_UNUSED(key); + Q_UNUSED(settings) +} + +/*! + Unregisters any additional values for the class \a key from the + system registry using the \a settings object. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 4 + + \sa registerClass(), QSettings +*/ +void QAxFactory::unregisterClass(const QString &key, QSettings *settings) const +{ + Q_UNUSED(key); + Q_UNUSED(settings) +} + +/*! + Reimplement this function to return true if \a licenseKey is a valid + license for the class \a key, or if the current machine is licensed. + + The default implementation returns true if the class \a key is + not licensed (ie. no \c Q_CLASSINFO() attribute "LicenseKey"), or + if \a licenseKey matches the value of the "LicenseKey" + attribute, or if the machine is licensed through a .LIC file with + the same filename as this COM server. +*/ +bool QAxFactory::validateLicenseKey(const QString &key, const QString &licenseKey) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return true; + + QString classKey = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value()); + if (classKey.isEmpty()) + return true; + + if (licenseKey.isEmpty()) { + QString licFile(QString::fromWCharArray(qAxModuleFilename)); + int lastDot = licFile.lastIndexOf(QLatin1Char('.')); + licFile = licFile.left(lastDot) + QLatin1String(".lic"); + if (QFile::exists(licFile)) + return true; + return false; + } + return licenseKey == classKey; +} + +/*! + Reimplement this function to return the name of the super class of + \a key up to which methods and properties should be exposed by the + ActiveX control. + + The default implementation interprets \a key as the class name, + and returns the value of the \c Q_CLASSINFO() entry + "ToSuperClass". If no such value is set the null-string is + returned, and the functions and properties of all the super + classes including QWidget will be exposed. + + To only expose the functions and properties of the class itself, + reimplement this function to return \a key. +*/ +QString QAxFactory::exposeToSuperClass(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QString(); + return QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("ToSuperClass")).value()); +} + +/*! + Reimplement this function to return true if the ActiveX control \a key + should be a top level window, e.g. a dialog. The default implementation + returns false. +*/ +bool QAxFactory::stayTopLevel(const QString &key) const +{ + return false; +} + +/*! + Reimplement this function to return true if the ActiveX control + \a key should support the standard ActiveX events + \list + \i Click + \i DblClick + \i KeyDown + \i KeyPress + \i KeyUp + \i MouseDown + \i MouseUp + \i MouseMove + \endlist + + The default implementation interprets \a key as the class name, + and returns true if the value of the \c Q_CLASSINFO() entry + "StockEvents" is "yes". Otherwise this function returns false. +*/ +bool QAxFactory::hasStockEvents(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return false; + return QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("StockEvents")).value()) == QLatin1String("yes"); +} + + +extern bool qAxIsServer; + +/*! + Returns true if the application has been started (by COM) as an ActiveX + server, otherwise returns false. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 5 +*/ + +bool QAxFactory::isServer() +{ + return qAxIsServer; +} + +extern wchar_t qAxModuleFilename[MAX_PATH]; + +/*! + Returns the directory that contains the server binary. + + For out-of-process servers this is the same as + QApplication::applicationDirPath(). For in-process servers + that function returns the directory that contains the hosting + application. +*/ +QString QAxFactory::serverDirPath() +{ + return QFileInfo(QString::fromWCharArray(qAxModuleFilename)).absolutePath(); +} + +/*! + Returns the file path of the server binary. + + For out-of-process servers this is the same as + QApplication::applicationFilePath(). For in-process servers + that function returns the file path of the hosting application. +*/ +QString QAxFactory::serverFilePath() +{ + return QString::fromWCharArray(qAxModuleFilename); +} + +/*! + Reimplement this function to return true if the server is + running as a persistent service (e.g. an NT service) and should + not terminate even when all objects provided have been released. + + The default implementation returns false. +*/ +bool QAxFactory::isService() const +{ + return false; +} + +/*! + \enum QAxFactory::ServerType + + This enum specifies the different types of servers that can be + started with startServer. + + \value SingleInstance The server process can create only one instance of each + exported class. COM starts a new process for each request. This is typically + used in servers that export only one creatable class. + \value MultipleInstances The server can create multiple instances of + each exported class. This is the default. All instances will live in the same + thread, and will share static resources. +*/ + +/*! + \fn bool QAxFactory::startServer(ServerType type); + + Starts the COM server with \a type and returns true if successful, + otherwise returns false. + + Calling this function if the server is already running (or for an + in-process server) does nothing and returns true. + + The server is started automatically with \a type set to \c MultipleInstances + if the server executable has been started with the \c -activex + command line parameter. To switch to SingleInstance, call + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 6 + + in your own main() entry point function. +*/ + +/*! + \fn bool QAxFactory::stopServer(); + + Stops the COM server and returns true if successful, otherwise + returns false. + + Calling this function if the server is not running (or for an + in-process server) does nothing and returns true. + + Stopping the server will not invalidate existing objects, but no + new objects can be created from the existing server process. Usually + COM will start a new server process if additional objects are requested. + + The server is stopped automatically when the main() function returns. +*/ + +class ActiveObject : public QObject +{ +public: + ActiveObject(QObject *parent, QAxFactory *factory); + ~ActiveObject(); + + IDispatch *wrapper; + DWORD cookie; +}; + +ActiveObject::ActiveObject(QObject *parent, QAxFactory *factory) +: QObject(parent), wrapper(0), cookie(0) +{ + QLatin1String key(parent->metaObject()->className()); + + factory->createObjectWrapper(parent, &wrapper); + if (wrapper) + RegisterActiveObject(wrapper, QUuid(factory->classID(key)), ACTIVEOBJECT_STRONG, &cookie); +} + +ActiveObject::~ActiveObject() +{ + if (cookie) + RevokeActiveObject(cookie, 0); + if (wrapper) + wrapper->Release(); +} + +/*! + Registers the QObject \a object with COM as a running object, and returns true if + the registration succeeded, otherwise returns false. The object is unregistered + automatically when it is destroyed. + + This function should only be called if the application has been started by the user + (i.e. not by COM to respond to a request), and only for one object, usually the + toplevel object of the application's object hierarchy. + + This function does nothing and returns false if the object's class info for + "RegisterObject" is not set to "yes", or if the server is an in-process server. +*/ +bool QAxFactory::registerActiveObject(QObject *object) +{ + if (qstricmp(object->metaObject()->classInfo(object->metaObject()->indexOfClassInfo("RegisterObject")).value(), "yes")) + return false; + + if (!QString::fromWCharArray(qAxModuleFilename).toLower().endsWith(QLatin1String(".exe"))) + return false; + + ActiveObject *active = new ActiveObject(object, qAxFactory()); + if (!active->wrapper || !active->cookie) { + delete active; + return false; + } + return true; +} + +/*! + \macro QAXFACTORY_DEFAULT(Class, ClassID, InterfaceID, EventID, LibID, AppID) + \relates QAxFactory + + This macro can be used to export a single QObject subclass \a Class a this + COM server through an implicitly declared QAxFactory implementation. + + This macro exports the class \a Class as a COM coclass with the CLSID \a ClassID. + The properties and slots will be declared through a COM interface with the IID + \a InterfaceID, and signals will be declared through a COM event interface with + the IID \a EventID. All declarations will be in a type library with the id \a LibID, + and if the server is an executable server then it will have the application id + \a AppID. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 7 + + \sa QAXFACTORY_EXPORT(), QAXFACTORY_BEGIN() +*/ + +/*! + \macro QAXFACTORY_EXPORT(Class, LibID, AppID) + \relates QAxFactory + + This macro can be used to export a QAxFactory implementation \a Class from + a COM server. All declarations will be in a type library with the id \a LibID, + and if the server is an executable server then it will have the application id + \a AppID. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 8 + + \sa QAXFACTORY_BEGIN() +*/ + +/*! + \macro QAXFACTORY_BEGIN(IDTypeLib, IDApp) + \relates QAxFactory + + This macro can be used to export multiple QObject classes through an + implicitly declared QAxFactory implementation. All QObject classes have to + declare the ClassID, InterfaceID and EventsID (if applicable) through the + Q_CLASSINFO() macro. All declarations will be in a type library with the id + \a IDTypeLib, and if the server is an executable server then it will have the + application id \a IDApp. + + This macro needs to be used together with the QAXCLASS(), QAXTYPE() + and QAXFACTORY_END() macros. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 9 +*/ + +/*! + \macro QAXCLASS(Class) + \relates QAxFactory + + This macro adds a creatable COM class \a Class to the QAxFactory declared + with the QAXFACTORY_BEGIN() macro. + + \sa QAXFACTORY_BEGIN(), QAXTYPE(), QAXFACTORY_END(), Q_CLASSINFO() +*/ + +/*! + \macro QAXTYPE(Class) + \relates QAxFactory + + This macro adds a non-creatable COM class \a Class to the QAxFactory + declared with the QAXFACTORY_BEGIN(). The class \a Class can be used + in APIs of other COM classes exported through QAXTYPE() or QAXCLASS(). + + Instances of type \a Class can only be retrieved using APIs of already + instantiated objects. + + \sa QAXFACTORY_BEGIN(), QAXCLASS(), QAXFACTORY_END(), Q_CLASSINFO() +*/ + +/*! + \macro QAXFACTORY_END() + \relates QAxFactory + + Completes the QAxFactory declaration started with the QAXFACTORY_BEGIN() + macro. + + \sa QAXFACTORY_BEGIN(), QAXCLASS(), QAXTYPE() +*/ + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/control/qaxfactory.h b/src/activeqt/control/qaxfactory.h new file mode 100644 index 0000000..25650ad --- /dev/null +++ b/src/activeqt/control/qaxfactory.h @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXFACTORY_H +#define QAXFACTORY_H + +#include <QtCore/qhash.h> +#include <QtCore/quuid.h> +#include <QtCore/qfactoryinterface.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qstringlist.h> + +struct IUnknown; +struct IDispatch; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +class QWidget; +class QSettings; + +class QAxFactory : public QObject +{ +public: + QAxFactory(const QUuid &libId, const QUuid &appId); + virtual ~QAxFactory(); + + virtual QStringList featureList() const = 0; + + virtual QObject *createObject(const QString &key) = 0; + virtual const QMetaObject *metaObject(const QString &key) const = 0; + virtual bool createObjectWrapper(QObject *object, IDispatch **wrapper); + + virtual QUuid classID(const QString &key) const; + virtual QUuid interfaceID(const QString &key) const; + virtual QUuid eventsID(const QString &key) const; + + virtual QUuid typeLibID() const; + virtual QUuid appID() const; + + virtual void registerClass(const QString &key, QSettings *) const; + virtual void unregisterClass(const QString &key, QSettings *) const; + + virtual bool validateLicenseKey(const QString &key, const QString &licenseKey) const; + + virtual QString exposeToSuperClass(const QString &key) const; + virtual bool stayTopLevel(const QString &key) const; + virtual bool hasStockEvents(const QString &key) const; + virtual bool isService() const; + + enum ServerType { + SingleInstance, + MultipleInstances + }; + + static bool isServer(); + static QString serverDirPath(); + static QString serverFilePath(); + static bool startServer(ServerType type = MultipleInstances); + static bool stopServer(); + + static bool registerActiveObject(QObject *object); + +private: + QUuid typelib; + QUuid app; +}; + +extern QAxFactory *qAxFactory(); + +extern bool qax_startServer(QAxFactory::ServerType); + +inline bool QAxFactory::startServer(ServerType type) +{ + // implementation in qaxservermain.cpp + return qax_startServer(type); +} + +extern bool qax_stopServer(); + +inline bool QAxFactory::stopServer() +{ + // implementation in qaxservermain.cpp + return qax_stopServer(); +} + +#define QAXFACTORY_EXPORT(IMPL, TYPELIB, APPID) \ + QT_BEGIN_NAMESPACE \ + QAxFactory *qax_instantiate() \ + { \ + IMPL *impl = new IMPL(QUuid(TYPELIB), QUuid(APPID)); \ + return impl; \ + } \ + QT_END_NAMESPACE + +#define QAXFACTORY_DEFAULT(Class, IIDClass, IIDInterface, IIDEvents, IIDTypeLib, IIDApp) \ + QT_BEGIN_NAMESPACE \ + class QAxDefaultFactory : public QAxFactory \ + { \ + public: \ + QAxDefaultFactory(const QUuid &app, const QUuid &lib) \ + : QAxFactory(app, lib), className(QLatin1String(#Class)) {} \ + QStringList featureList() const \ + { \ + QStringList list; \ + list << className; \ + return list; \ + } \ + const QMetaObject *metaObject(const QString &key) const \ + { \ + if (key == className) \ + return &Class::staticMetaObject; \ + return 0; \ + } \ + QObject *createObject(const QString &key) \ + { \ + if (key == className) \ + return new Class(0); \ + return 0; \ + } \ + QUuid classID(const QString &key) const \ + { \ + if (key == className) \ + return QUuid(IIDClass); \ + return QUuid(); \ + } \ + QUuid interfaceID(const QString &key) const \ + { \ + if (key == className) \ + return QUuid(IIDInterface); \ + return QUuid(); \ + } \ + QUuid eventsID(const QString &key) const \ + { \ + if (key == className) \ + return QUuid(IIDEvents); \ + return QUuid(); \ + } \ + private: \ + QString className; \ + }; \ + QT_END_NAMESPACE \ + QAXFACTORY_EXPORT(QAxDefaultFactory, IIDTypeLib, IIDApp) \ + +template<class T> +class QAxClass : public QAxFactory +{ +public: + QAxClass(const QString &libId, const QString &appId) + : QAxFactory(libId, appId) + {} + + const QMetaObject *metaObject(const QString &) const { return &T::staticMetaObject; } + QStringList featureList() const { return QStringList(QString(T::staticMetaObject.className())); } + QObject *createObject(const QString &key) + { + const QMetaObject &mo = T::staticMetaObject; + if (key != QLatin1String(mo.className())) + return 0; + if (!qstrcmp(mo.classInfo(mo.indexOfClassInfo("Creatable")).value(), "no")) + return 0; + return new T(0); + } +}; + +#define QAXFACTORY_BEGIN(IDTypeLib, IDApp) \ + QT_BEGIN_NAMESPACE \ + class QAxFactoryList : public QAxFactory \ + { \ + QStringList factoryKeys; \ + QHash<QString, QAxFactory*> factories; \ + QHash<QString, bool> creatable; \ + public: \ + QAxFactoryList() \ + : QAxFactory(IDTypeLib, IDApp) \ + { \ + QAxFactory *factory = 0; \ + QStringList keys; \ + QStringList::Iterator it; \ + +#define QAXCLASS(Class) \ + factory = new QAxClass<Class>(typeLibID(), appID()); \ + qRegisterMetaType<Class*>(#Class"*"); \ + keys = factory->featureList(); \ + for (it = keys.begin(); it != keys.end(); ++it) { \ + factoryKeys += *it; \ + factories.insert(*it, factory); \ + creatable.insert(*it, true); \ + }\ + +#define QAXTYPE(Class) \ + factory = new QAxClass<Class>(typeLibID(), appID()); \ + qRegisterMetaType<Class*>(#Class"*"); \ + keys = factory->featureList(); \ + for (it = keys.begin(); it != keys.end(); ++it) { \ + factoryKeys += *it; \ + factories.insert(*it, factory); \ + creatable.insert(*it, false); \ + }\ + +#define QAXFACTORY_END() \ + } \ + ~QAxFactoryList() { qDeleteAll(factories); } \ + QStringList featureList() const { return factoryKeys; } \ + const QMetaObject *metaObject(const QString&key) const { \ + QAxFactory *f = factories[key]; \ + return f ? f->metaObject(key) : 0; \ + } \ + QObject *createObject(const QString &key) { \ + if (!creatable.value(key)) \ + return 0; \ + QAxFactory *f = factories[key]; \ + return f ? f->createObject(key) : 0; \ + } \ + QUuid classID(const QString &key) { \ + QAxFactory *f = factories.value(key); \ + return f ? f->classID(key) : QUuid(); \ + } \ + QUuid interfaceID(const QString &key) { \ + QAxFactory *f = factories.value(key); \ + return f ? f->interfaceID(key) : QUuid(); \ + } \ + QUuid eventsID(const QString &key) { \ + QAxFactory *f = factories.value(key); \ + return f ? f->eventsID(key) : QUuid(); \ + } \ + void registerClass(const QString &key, QSettings *s) const { \ + QAxFactory *f = factories.value(key); \ + if (f) f->registerClass(key, s); \ + } \ + void unregisterClass(const QString &key, QSettings *s) const { \ + QAxFactory *f = factories.value(key); \ + if (f) f->unregisterClass(key, s); \ + } \ + QString exposeToSuperClass(const QString &key) const { \ + QAxFactory *f = factories.value(key); \ + return f ? f->exposeToSuperClass(key) : QString(); \ + } \ + bool stayTopLevel(const QString &key) const { \ + QAxFactory *f = factories.value(key); \ + return f ? f->stayTopLevel(key) : false; \ + } \ + bool hasStockEvents(const QString &key) const { \ + QAxFactory *f = factories.value(key); \ + return f ? f->hasStockEvents(key) : false; \ + } \ + }; \ + QAxFactory *qax_instantiate() \ + { \ + QAxFactoryList *impl = new QAxFactoryList(); \ + return impl; \ + } \ + QT_END_NAMESPACE + +QT_END_NAMESPACE + +#ifndef Q_COM_METATYPE_DECLARED +#define Q_COM_METATYPE_DECLARED + +Q_DECLARE_METATYPE(IUnknown*) +Q_DECLARE_METATYPE(IDispatch*) + +#endif + +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXFACTORY_H diff --git a/src/activeqt/control/qaxmain.cpp b/src/activeqt/control/qaxmain.cpp new file mode 100644 index 0000000..3d1e6c8 --- /dev/null +++ b/src/activeqt/control/qaxmain.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qapplication.h> +#include <qaxfactory.h> + +#ifndef QT_NO_WIN_ACTIVEQT + +int main(int argc, char **argv) +{ + QT_USE_NAMESPACE + QAxFactory::startServer(); + QApplication app(argc, argv); + app.setQuitOnLastWindowClosed(false); + + return app.exec(); +} +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/control/qaxserver.cpp b/src/activeqt/control/qaxserver.cpp new file mode 100644 index 0000000..1726f92 --- /dev/null +++ b/src/activeqt/control/qaxserver.cpp @@ -0,0 +1,1257 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxbindable.h" +#include "qaxfactory.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qapplication.h> +#include <qdatetime.h> +#include <qdir.h> +#include <qmap.h> +#include <qmenubar.h> +#include <qmetaobject.h> +#include <qsettings.h> +#include <qvariant.h> +#include <qtextstream.h> + +#include <qt_windows.h> +#include <olectl.h> + +QT_BEGIN_NAMESPACE + +#define Q_REQUIRED_RPCNDR_H_VERSION 475 + +// Some global variables to store module information +bool qAxIsServer = false; +HANDLE qAxInstance = 0; +ITypeLib *qAxTypeLibrary = 0; +wchar_t qAxModuleFilename[MAX_PATH]; +bool qAxOutProcServer = false; + +// The QAxFactory instance +static QAxFactory* qax_factory = 0; +extern CLSID CLSID_QRect; +extern CLSID CLSID_QSize; +extern CLSID CLSID_QPoint; +extern void qax_shutDown(); +extern bool qax_ownQApp; + + +extern QAxFactory *qax_instantiate(); + +QAxFactory *qAxFactory() +{ + if (!qax_factory) { + bool hadQApp = qApp != 0; + qax_factory = qax_instantiate(); + // QAxFactory created a QApplication + if (!hadQApp && qApp) + qax_ownQApp = true; + + // register all types with metatype system as pointers + QStringList keys(qax_factory->featureList()); + for (int i = 0; i < keys.count(); ++i) { + QString key(keys.at(i)); + qRegisterMetaType((key + QLatin1Char('*')).toLatin1(), (void**)0); + } + } + return qax_factory; +} + +// Some local variables to handle module lifetime +static unsigned long qAxModuleRef = 0; +static CRITICAL_SECTION qAxModuleSection; + + +///////////////////////////////////////////////////////////////////////////// +// Server control +///////////////////////////////////////////////////////////////////////////// + +static int initCount = 0; + +QString qAxInit() +{ + static QString libFile; + + if (initCount++) + return libFile; + + InitializeCriticalSection(&qAxModuleSection); + + libFile = QString::fromWCharArray(qAxModuleFilename); + libFile = libFile.toLower(); + if (LoadTypeLibEx((wchar_t*)libFile.utf16(), REGKIND_NONE, &qAxTypeLibrary) == S_OK) + return libFile; + + int lastDot = libFile.lastIndexOf(QLatin1Char('.')); + libFile = libFile.left(lastDot) + QLatin1String(".tlb"); + if (LoadTypeLibEx((wchar_t*)libFile.utf16(), REGKIND_NONE, &qAxTypeLibrary) == S_OK) + return libFile; + + lastDot = libFile.lastIndexOf(QLatin1Char('.')); + libFile = libFile.left(lastDot) + QLatin1String(".olb"); + if (LoadTypeLibEx((wchar_t*)libFile.utf16(), REGKIND_NONE, &qAxTypeLibrary) == S_OK) + return libFile; + + libFile = QString(); + return libFile; +} + +void qAxCleanup() +{ + if (!initCount) + qWarning("qAxInit/qAxCleanup mismatch"); + + if (--initCount) + return; + + delete qax_factory; + qax_factory = 0; + + if (qAxTypeLibrary) { + qAxTypeLibrary->Release(); + qAxTypeLibrary = 0; + } + + DeleteCriticalSection(&qAxModuleSection); +} + +unsigned long qAxLock() +{ + EnterCriticalSection(&qAxModuleSection); + unsigned long ref = ++qAxModuleRef; + LeaveCriticalSection(&qAxModuleSection); + return ref; +} + +unsigned long qAxUnlock() +{ + if (!initCount) // cleaned up already + return 0; + + EnterCriticalSection(&qAxModuleSection); + unsigned long ref = --qAxModuleRef; + LeaveCriticalSection(&qAxModuleSection); + + if (!ref) + qax_shutDown(); + return ref; +} + +unsigned long qAxLockCount() +{ + return qAxModuleRef; +} + +///////////////////////////////////////////////////////////////////////////// +// Registry +///////////////////////////////////////////////////////////////////////////// + +extern bool qax_disable_inplaceframe; + +QString qax_clean_type(const QString &type, const QMetaObject *mo) +{ + if (mo) { + int classInfoIdx = mo->indexOfClassInfo("CoClassAlias"); + if (classInfoIdx != -1) { + const QMetaClassInfo classInfo = mo->classInfo(classInfoIdx); + return QLatin1String(classInfo.value()); + } + } + + QString alias(type); + alias.remove(QLatin1String("::")); + return alias; +} + +// (Un)Register the ActiveX server in the registry. +// The QAxFactory implementation provides the information. +HRESULT UpdateRegistry(BOOL bRegister) +{ + qAxIsServer = false; + QString file = QString::fromWCharArray(qAxModuleFilename); + QString path = file.left(file.lastIndexOf(QLatin1Char('\\'))+1); + QString module = file.right(file.length() - path.length()); + module = module.left(module.lastIndexOf(QLatin1Char('.'))); + + const QString appId = qAxFactory()->appID().toString().toUpper(); + const QString libId = qAxFactory()->typeLibID().toString().toUpper(); + + QString libFile = qAxInit(); + QString typeLibVersion; + + TLIBATTR *libAttr = 0; + if (qAxTypeLibrary) + qAxTypeLibrary->GetLibAttr(&libAttr); + if (!libAttr) + return SELFREG_E_TYPELIB; + + DWORD major = libAttr->wMajorVerNum; + DWORD minor = libAttr->wMinorVerNum; + typeLibVersion = QString::number((uint)major) + QLatin1Char('.') + QString::number((uint)minor); + + if (bRegister) + RegisterTypeLib(qAxTypeLibrary, (wchar_t*)libFile.utf16(), 0); + else + UnRegisterTypeLib(libAttr->guid, libAttr->wMajorVerNum, libAttr->wMinorVerNum, libAttr->lcid, libAttr->syskind); + + qAxTypeLibrary->ReleaseTLibAttr(libAttr); + + if (typeLibVersion.isEmpty()) + typeLibVersion = QLatin1String("1.0"); + + // check whether the user has permission to write to HKLM\Software\Classes + // if not, use HKCU\Software\Classes + QString keyPath(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes")); + QSettings test(keyPath, QSettings::NativeFormat); + if (!test.isWritable()) + keyPath = QLatin1String("HKEY_CURRENT_USER\\Software\\Classes"); + + QSettings settings(keyPath, QSettings::NativeFormat); + + // we try to create the ActiveX widgets later on... + bool delete_qApp = false; + if (!qApp) { + int argc = 0; + (void)new QApplication(argc, 0); + delete_qApp = true; + } + + if (bRegister) { + if (qAxOutProcServer) { + settings.setValue(QLatin1String("/AppID/") + appId + QLatin1String("/."), module); + settings.setValue(QLatin1String("/AppID/") + module + QLatin1String(".EXE/AppID"), appId); + } + + QStringList keys = qAxFactory()->featureList(); + for (QStringList::Iterator key = keys.begin(); key != keys.end(); ++key) { + QString className = *key; + QObject *object = qAxFactory()->createObject(className); + const QMetaObject *mo = qAxFactory()->metaObject(className); + const QString classId = qAxFactory()->classID(className).toString().toUpper(); + + className = qax_clean_type(className, mo); + + if (object) { // don't register subobject classes + QString classVersion = mo ? QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("Version")).value()) : QString(); + if (classVersion.isNull()) + classVersion = QLatin1String("1.0"); + bool insertable = mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Insertable")).value(), "yes"); + bool control = object->isWidgetType(); + const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1Char('.'))); + uint olemisc = OLEMISC_SETCLIENTSITEFIRST + |OLEMISC_ACTIVATEWHENVISIBLE + |OLEMISC_INSIDEOUT + |OLEMISC_CANTLINKINSIDE + |OLEMISC_RECOMPOSEONRESIZE; + if (!control) + olemisc |= OLEMISC_INVISIBLEATRUNTIME; + else if (object->findChild<QMenuBar*>() && !qax_disable_inplaceframe) + olemisc |= OLEMISC_WANTSTOMENUMERGE; + + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/."), className + QLatin1String(" Class")); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/CLSID/."), classId); + if (insertable) + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/Insertable/."), QVariant(QLatin1String(""))); + + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/."), className + QLatin1String(" Class")); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CLSID/."), classId); + settings.setValue(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CurVer/."), module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion); + + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/."), className + QLatin1String(" Class")); + if (file.endsWith(QLatin1String("exe"), Qt::CaseInsensitive)) + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/AppID"), appId); + if (control) + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Control/."), QVariant(QLatin1String(""))); + if (insertable) + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Insertable/."), QVariant(QLatin1String(""))); + if (file.right(3).toLower() == QLatin1String("dll")) + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/InProcServer32/."), file); + else + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/LocalServer32/."), + QLatin1Char('\"') + file + QLatin1String("\" -activex")); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/."), control ? QLatin1String("1") : QLatin1String("0")); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/1/."), QString::number(olemisc)); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Programmable/."), QVariant(QLatin1String(""))); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ToolboxBitmap32/."), QLatin1Char('\"') + + file + QLatin1String("\", 101")); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/TypeLib/."), libId); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Version/."), classVersion); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/VersionIndependentProgID/."), module + QLatin1Char('.') + className); + settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ProgID/."), module + QLatin1Char('.') + className + QLatin1Char('.') + classVersion.left(classVersion.indexOf(QLatin1Char('.')))); + + QString mime = QLatin1String(mo->classInfo(mo->indexOfClassInfo("MIME")).value()); + if (!mime.isEmpty()) { + QStringList mimeTypes = mime.split(QLatin1Char(';')); + for (int m = 0; m < mimeTypes.count(); ++m) { + mime = mimeTypes.at(m); + if (mime.isEmpty()) + continue; + QString extension; + while (mime.contains(QLatin1Char(':'))) { + extension = mime.mid(mime.lastIndexOf(QLatin1Char(':')) + 1); + mime = mime.left(mime.length() - extension.length() - 1); + // Prepend '.' before extension, if required. + extension = extension.trimmed(); + if (extension[0] != QLatin1Char('.')) + extension = QLatin1Char('.') + extension; + } + + if (!extension.isEmpty()) { + settings.setValue(QLatin1Char('/') + extension + QLatin1String("/."), module + QLatin1Char('.') + className); + settings.setValue(QLatin1Char('/') + extension + QLatin1String("/Content Type"), mime); + + mime = mime.replace(QLatin1Char('/'), QLatin1Char('\\')); + settings.setValue(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/CLSID"), classId); + settings.setValue(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/Extension"), extension); + } + } + } + + delete object; + } + + qAxFactory()->registerClass(*key, &settings); + } + } else { + if (qAxOutProcServer) { + settings.remove(QLatin1String("/AppID/") + appId + QLatin1String("/.")); + settings.remove(QLatin1String("/AppID/") + module + QLatin1String(".EXE")); + } + QStringList keys = qAxFactory()->featureList(); + for (QStringList::Iterator key = keys.begin(); key != keys.end(); ++key) { + QString className = *key; + const QMetaObject *mo = qAxFactory()->metaObject(className); + const QString classId = qAxFactory()->classID(className).toString().toUpper(); + className = qax_clean_type(className, mo); + + QString classVersion = mo ? QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("Version")).value()) : QString(); + if (classVersion.isNull()) + classVersion = QLatin1String("1.0"); + const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1Char('.'))); + + qAxFactory()->unregisterClass(*key, &settings); + + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/CLSID/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/Insertable/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion + QLatin1String("/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1Char('.') + classMajorVersion); + + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CLSID/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/CurVer/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className + QLatin1String("/.")); + settings.remove(QLatin1Char('/') + module + QLatin1Char('.') + className); + + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/AppID")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Control/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Insertable/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/InProcServer32/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/LocalServer32/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/1/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Programmable/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/ToolboxBitmap32/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/TypeLib/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Version/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/VersionIndependentProgID/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/ProgID/.")); + settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/.")); + settings.remove(QLatin1String("/CLSID/") + classId); + + QString mime = QLatin1String(mo->classInfo(mo->indexOfClassInfo("MIME")).value()); + if (!mime.isEmpty()) { + QStringList mimeTypes = mime.split(QLatin1Char(';')); + for (int m = 0; m < mimeTypes.count(); ++m) { + mime = mimeTypes.at(m); + if (mime.isEmpty()) + continue; + QString extension; + while (mime.contains(QLatin1Char(':'))) { + extension = mime.mid(mime.lastIndexOf(QLatin1Char(':')) + 1); + mime = mime.left(mime.length() - extension.length() - 1); + // Prepend '.' before extension, if required. + extension = extension.trimmed(); + if (extension[0] != QLatin1Char('.')) + extension.prepend(QLatin1Char('.')); + } + if (!extension.isEmpty()) { + settings.remove(QLatin1Char('/') + extension + QLatin1String("/Content Type")); + settings.remove(QLatin1Char('/') + extension + QLatin1String("/.")); + settings.remove(QLatin1Char('/') + extension); + mime.replace(QLatin1Char('/'), QLatin1Char('\\')); + settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/Extension")); + settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/CLSID")); + settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/.")); + settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime); + } + } + } + } + } + + if (delete_qApp) + delete qApp; + + qAxCleanup(); + if (settings.status() == QSettings::NoError) + return S_OK; + return SELFREG_E_CLASS; +} + +///////////////////////////////////////////////////////////////////////////// +// IDL generator +///////////////////////////////////////////////////////////////////////////// + +static QList<QByteArray> enums; +static QList<QByteArray> enumValues; +static QList<QByteArray> subtypes; + +static const char* const type_map[][2] = +{ + // QVariant/Qt Value data types + { "QString", "BSTR" }, + { "QCString", "BSTR" }, + { "bool", "VARIANT_BOOL" }, + { "int", "int" }, + { "uint", "unsigned int" }, + { "double", "double" }, + { "QColor", "OLE_COLOR" }, + { "QDate", "DATE" }, + { "QTime", "DATE" }, + { "QDateTime", "DATE" }, + { "QFont", "IFontDisp*" }, + { "QPixmap", "IPictureDisp*" }, + { "QVariant", "VARIANT" }, + { "QVariantList", "SAFEARRAY(VARIANT)" }, + { "QList<QVariant>", "SAFEARRAY(VARIANT)" }, + { "quint64", "CY" }, + { "qint64", "CY" }, + { "qulonglong", "CY" }, + { "qlonglong", "CY" }, + { "QByteArray", "SAFEARRAY(BYTE)" }, + { "QStringList", "SAFEARRAY(BSTR)" }, + // Userdefined Qt datatypes - some not on Borland though + { "QCursor", "enum MousePointer" }, + { "Qt::FocusPolicy", "enum FocusPolicy" }, +#ifndef Q_CC_BOR +# if __REQUIRED_RPCNDR_H_VERSION__ >= Q_REQUIRED_RPCNDR_H_VERSION + { "QRect", "struct QRect" }, + { "QSize", "struct QSize" }, + { "QPoint", "struct QPoint" }, +# endif +#endif + // And we support COM data types + { "BOOL", "BOOL" }, + { "BSTR", "BSTR" }, + { "OLE_COLOR", "OLE_COLOR" }, + { "DATE", "DATE" }, + { "VARIANT", "VARIANT" }, + { "IDispatch", "IDispatch*" }, + { "IUnknown", "IUnknown*" }, + { "IDispatch*", "IDispatch*" }, + { "IUnknown*", "IUnknown*" }, + { 0, 0 } +}; + +static QByteArray convertTypes(const QByteArray &qtype, bool *ok) +{ + qRegisterMetaType("IDispatch*", (void**)0); + qRegisterMetaType("IUnknown*", (void**)0); + + *ok = false; + + int i = 0; + while (type_map[i][0]) { + if (qtype == type_map[i][0] && type_map[i][1]) { + *ok = true; + return type_map[i][1]; + } + ++i; + } + if (enums.contains(qtype)) { + *ok = true; + return "enum " + qtype; + } + if (subtypes.contains(qtype)) { + *ok = true; + } else if (qtype.endsWith('*')) { + QByteArray cleanType = qtype.left(qtype.length() - 1); + const QMetaObject *mo = qAxFactory()->metaObject(QString::fromLatin1(cleanType.constData())); + if (mo) { + cleanType = qax_clean_type(QString::fromLatin1(cleanType), mo).toLatin1(); + if (subtypes.contains(cleanType)) { + *ok = true; + return cleanType + '*'; + } + } + } + return qtype; +} + +static const char* const keyword_map[][2] = +{ + { "aggregatable", "aggregating" }, + { "allocate", "alloc" }, + { "appobject", "appObject" }, + { "arrays", "array" }, + { "async", "asynchronous" }, + { "bindable", "binding" }, + { "Boolean", "boolval" }, + { "boolean", "boolval" }, + { "broadcast", "broadCast" }, + { "callback", "callBack" }, + { "decode", "deCode" }, + { "default", "defaulted" }, + { "defaultbind", "defaultBind" }, + { "defaultvalue", "defaultValue" }, + { "encode" "enCode" }, + { "endpoint", "endPoint" }, + { "hidden", "isHidden" }, + { "ignore", "ignore_" }, + { "local", "local_" }, + { "notify", "notify_" }, + { "object", "object_" }, + { "optimize", "optimize_" }, + { "optional", "optional_" }, + { "out", "out_" }, + { "pipe", "pipe_" }, + { "proxy", "proxy_" }, + { "ptr", "pointer" }, + { "readonly", "readOnly" }, + { "small", "small_" }, + { "source", "source_" }, + { "string", "string_" }, + { "uuid", "uuid_" }, + { 0, 0 } +}; + +static QByteArray replaceKeyword(const QByteArray &name) +{ + int i = 0; + while (keyword_map[i][0]) { + if (name == keyword_map[i][0] && keyword_map[i][1]) + return keyword_map[i][1]; + ++i; + } + return name; +} + +static QMap<QByteArray, int> mapping; + +static QByteArray renameOverloads(const QByteArray &name) +{ + QByteArray newName = name; + + int n = mapping.value(name); + if (mapping.contains(name)) { + int n = mapping.value(name); + newName = name + '_' + QByteArray::number(n); + mapping.insert(name, n+1); + } else { + mapping.insert(name, 1); + } + + return newName; +} + +// filter out some properties +static const char* const ignore_props[] = +{ + "name", + "objectName", + "isTopLevel", + "isDialog", + "isModal", + "isPopup", + "isDesktop", + "geometry", + "pos", + "frameSize", + "frameGeometry", + "size", + "sizeHint", + "minimumSizeHint", + "microFocusHint", + "rect", + "childrenRect", + "childrenRegion", + "minimumSize", + "maximumSize", + "sizeIncrement", + "baseSize", + "ownPalette", + "ownFont", + "ownCursor", + "visibleRect", + "isActiveWindow", + "underMouse", + "visible", + "hidden", + "minimized", + "focus", + "focusEnabled", + "customWhatsThis", + "shown", + "windowOpacity", + 0 +}; + +// filter out some slots +static const char* const ignore_slots[] = +{ + "deleteLater", + "setMouseTracking", + "update", + "repaint", + "iconify", + "showMinimized", + "showMaximized", + "showFullScreen", + "showNormal", + "polish", + "constPolish", + "stackUnder", + "setShown", + "setHidden", + "move_1", + "resize_1", + "setGeometry_1", + 0 +}; + +static bool ignore(const char *test, const char *const *table) +{ + if (!test) + return true; + int i = 0; + while (table[i]) { + if (!strcmp(test, table[i])) + return true; + ++i; + } + return false; +} + +bool ignoreSlots(const char *test) +{ + return ignore(test, ignore_slots); +} + +bool ignoreProps(const char *test) +{ + return ignore(test, ignore_props); +} + +#define STRIPCB(x) x = x.mid(1, x.length()-2) + +static QByteArray prototype(const QList<QByteArray> ¶meterTypes, const QList<QByteArray> ¶meterNames, bool *ok) +{ + QByteArray prototype; + + for (int p = 0; p < parameterTypes.count() && *ok; ++p) { + bool out = false; + QByteArray type(parameterTypes.at(p)); + QByteArray name(parameterNames.at(p)); + + if (type.endsWith('&')) { + out = true; + type.truncate(type.length() - 1); + } else if (type.endsWith("**")) { + out = true; + type.truncate(type.length() - 1); + } else if (type.endsWith('*') && !subtypes.contains(type)) { + type.truncate(type.length() - 1); + } + if (type.isEmpty()) { + *ok = false; + break; + } + type = convertTypes(type, ok); + if (!out) + prototype += "[in] " + type + ' '; + else + prototype += "[in,out] " + type + ' '; + + if (out) + prototype += '*'; + if (name.isEmpty()) + prototype += 'p' + QByteArray::number(p); + else + prototype += "p_" + replaceKeyword(name); + + if (p < parameterTypes.count() - 1) + prototype += ", "; + } + + return prototype; +} + +static QByteArray addDefaultArguments(const QByteArray &prototype, int numDefArgs) +{ + // nothing to do, or unsupported anyway + if (!numDefArgs || prototype.contains("/**")) + return prototype; + + QByteArray ptype(prototype); + int in = -1; + while (numDefArgs) { + in = ptype.lastIndexOf(']', in); + ptype.replace(in, 1, ",optional]"); + in = ptype.indexOf(' ', in) + 1; + QByteArray type = ptype.mid(in, ptype.indexOf(' ', in) - in); + if (type == "enum") + type += ' ' + ptype.mid(in + 5, ptype.indexOf(' ', in + 5) - in - 5); + ptype.replace(in, type.length(), QByteArray("VARIANT /*was: ") + type + "*/"); + --numDefArgs; + } + + return ptype; +} + +static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &className, bool isBindable, QTextStream &out) +{ + int id = 1; + int i = 0; + if (!mo) + return 3; + + QString topclass = qAxFactory()->exposeToSuperClass(className); + if (topclass.isEmpty()) + topclass = QLatin1String("QObject"); + bool hasStockEvents = qAxFactory()->hasStockEvents(className); + + const QMetaObject *pmo = mo; + do { + pmo = pmo->superClass(); + } while (pmo && topclass != QString::fromLatin1(pmo->className())); + + int enumoff = pmo ? pmo->enumeratorOffset() : mo->enumeratorOffset(); + int methodoff = pmo ? pmo->methodOffset() : mo->methodOffset(); + int propoff = pmo ? pmo->propertyOffset() : mo->propertyOffset(); + + int qtProps = 0; + int qtSlots = 0; + + bool control = false; + + if (o && o->isWidgetType()) { + qtProps = QWidget::staticMetaObject.propertyCount(); + qtSlots = QWidget::staticMetaObject.methodCount(); + control = true; + } + + QString classID = qAxFactory()->classID(className).toString().toUpper(); + if (QUuid(classID).isNull()) + return 4; + STRIPCB(classID); + QString interfaceID = qAxFactory()->interfaceID(className).toString().toUpper(); + if (QUuid(interfaceID).isNull()) + return 5; + STRIPCB(interfaceID); + QString eventsID = qAxFactory()->eventsID(className).toString().toUpper(); + bool hasEvents = !QUuid(eventsID).isNull(); + STRIPCB(eventsID); + + QString cleanClassName = qax_clean_type(className, mo); + QString defProp(QLatin1String(mo->classInfo(mo->indexOfClassInfo("DefaultProperty")).value())); + QString defSignal(QLatin1String(mo->classInfo(mo->indexOfClassInfo("DefaultSignal")).value())); + + for (i = enumoff; i < mo->enumeratorCount(); ++i) { + const QMetaEnum enumerator = mo->enumerator(i); + if (enums.contains(enumerator.name())) + continue; + + enums.append(enumerator.name()); + + out << "\tenum " << enumerator.name() << " {" << endl; + + for (int j = 0; j < enumerator.keyCount(); ++j) { + QByteArray key(enumerator.key(j)); + while (enumValues.contains(key)) { + key += '_'; + } + enumValues.append(key); + uint value = (uint)enumerator.value(j); + key = key.leftJustified(20); + out << "\t\t" << key << "\t= "; + if (enumerator.isFlag()) + out << "0x" << QByteArray::number(value, 16).rightJustified(8, '0'); + else + out << value; + if (j < enumerator.keyCount()-1) + out << ", "; + out << endl; + } + out << "\t};" << endl << endl; + } + + // mouse cursor enum for QCursor support + if (!enums.contains("MousePointer")) { + enums.append("MousePointer"); + out << "\tenum MousePointer {" << endl; + out << "\t\tArrowCursor = " << Qt::ArrowCursor << ',' << endl; + out << "\t\tUpArrowCursor = " << Qt::UpArrowCursor << ',' << endl; + out << "\t\tCrossCursor = " << Qt::CrossCursor << ',' << endl; + out << "\t\tWaitCursor = " << Qt::WaitCursor << ',' << endl; + out << "\t\tIBeamCursor = " << Qt::IBeamCursor << ',' << endl; + out << "\t\tSizeVerCursor = " << Qt::SizeVerCursor << ',' << endl; + out << "\t\tSizeHorCursor = " << Qt::SizeHorCursor << ',' << endl; + out << "\t\tSizeBDiagCursor = " << Qt::SizeBDiagCursor << ',' << endl; + out << "\t\tSizeFDiagCursor = " << Qt::SizeFDiagCursor << ',' << endl; + out << "\t\tSizeAllCursor = " << Qt::SizeAllCursor << ',' << endl; + out << "\t\tBlankCursor = " << Qt::BlankCursor << ',' << endl; + out << "\t\tSplitVCursor = " << Qt::SplitVCursor << ',' << endl; + out << "\t\tSplitHCursor = " << Qt::SplitHCursor << ',' << endl; + out << "\t\tPointingHandCursor = " << Qt::PointingHandCursor << ',' << endl; + out << "\t\tForbiddenCursor = " << Qt::ForbiddenCursor << ',' << endl; + out << "\t\tWhatsThisCursor = " << Qt::WhatsThisCursor << ',' << endl; + out << "\t\tBusyCursor\t= " << Qt::BusyCursor << endl; + out << "\t};" << endl << endl; + } + if (!enums.contains("FocusPolicy")) { + enums.append("FocusPolicy"); + out << "\tenum FocusPolicy {" << endl; + out << "\t\tNoFocus = " << Qt::NoFocus << ',' << endl; + out << "\t\tTabFocus = " << Qt::TabFocus << ',' << endl; + out << "\t\tClickFocus = " << Qt::ClickFocus << ',' << endl; + out << "\t\tStrongFocus = " << Qt::StrongFocus << ',' << endl; + out << "\t\tWheelFocus = " << Qt::WheelFocus << endl; + out << "\t};" << endl << endl; + } + + out << endl; + out << "\t[" << endl; + out << "\t\tuuid(" << interfaceID << ")," << endl; + out << "\t\thelpstring(\"" << cleanClassName << " Interface\")" << endl; + out << "\t]" << endl; + out << "\tdispinterface I" << cleanClassName << endl; + out << "\t{" << endl; + + out << "\tproperties:" << endl; + for (i = propoff; i < mo->propertyCount(); ++i) { + const QMetaProperty property = mo->property(i); + /* if (property.testFlags(QMetaProperty::Override)) + continue;*/ + if (i <= qtProps && ignoreProps(property.name())) + continue; + if (!property.name() || mo->indexOfProperty(property.name()) > i) + continue; + + bool ok = true; + QByteArray type(convertTypes(property.typeName(), &ok)); + QByteArray name(replaceKeyword(property.name())); + + if (!ok) + out << "\t/****** Property is of unsupported datatype" << endl; + + out << "\t\t[id(" << id << ')'; + if (!property.isWritable()) + out << ", readonly"; + if (isBindable && property.isScriptable(o)) + out << ", bindable"; + if (!property.isDesignable(o)) + out << ", nonbrowsable"; + if (isBindable) + out << ", requestedit"; + if (defProp == QLatin1String(name)) + out << ", uidefault"; + out << "] " << type << ' ' << name << ';' << endl; + + if (!ok) + out << "\t******/" << endl; + ++id; + } + out << endl; + out << "\tmethods:" << endl; + int numDefArgs = 0; + QByteArray outBuffer; + for (i = methodoff; i < mo->methodCount(); ++i) { + const QMetaMethod slot = mo->method(i); + if (slot.access() != QMetaMethod::Public || slot.methodType() == QMetaMethod::Signal) + continue; + + if (slot.attributes() & QMetaMethod::Cloned) { + ++numDefArgs; + continue; + } + if (!outBuffer.isEmpty()) { + outBuffer = addDefaultArguments(outBuffer, numDefArgs); + numDefArgs = 0; + out << outBuffer; + outBuffer = QByteArray(); + } + + QByteArray signature(slot.signature()); + QByteArray name(signature.left(signature.indexOf('('))); + if (i <= qtSlots && ignoreSlots(name)) + continue; + + signature = signature.mid(name.length() + 1); + signature.truncate(signature.length() - 1); + name = renameOverloads(replaceKeyword(name)); + if (ignoreSlots(name)) + continue; + + QList<QByteArray> parameterTypes(slot.parameterTypes()); + QList<QByteArray> parameterNames(slot.parameterNames()); + + bool ok = true; + QByteArray type = slot.typeName(); + if (type.isEmpty()) + type = "void"; + else + type = convertTypes(type, &ok); + + QByteArray ptype(prototype(parameterTypes, parameterNames, &ok)); + if (!ok) + outBuffer += "\t/****** Slot parameter uses unsupported datatype\n"; + + outBuffer += "\t\t[id(" + QString::number(id).toLatin1() + ")] " + type + ' ' + name + '(' + ptype + ");\n"; + + if (!ok) + outBuffer += "\t******/\n"; + ++id; + } + if (!outBuffer.isEmpty()) { + outBuffer = addDefaultArguments(outBuffer, numDefArgs); + numDefArgs = 0; + out << outBuffer; + outBuffer = QByteArray(); + } + out << "\t};" << endl << endl; + + mapping.clear(); + id = 1; + + if (hasEvents) { + out << "\t[" << endl; + out << "\t\tuuid(" << eventsID << ")," << endl; + out << "\t\thelpstring(\"" << cleanClassName << " Events Interface\")" << endl; + out << "\t]" << endl; + out << "\tdispinterface I" << cleanClassName << "Events" << endl; + out << "\t{" << endl; + out << "\tproperties:" << endl; + out << "\tmethods:" << endl; + + if (hasStockEvents) { + out << "\t/****** Stock events ******/" << endl; + out << "\t\t[id(DISPID_CLICK)] void Click();" << endl; + out << "\t\t[id(DISPID_DBLCLICK)] void DblClick();" << endl; + out << "\t\t[id(DISPID_KEYDOWN)] void KeyDown(short* KeyCode, short Shift);" << endl; + out << "\t\t[id(DISPID_KEYPRESS)] void KeyPress(short* KeyAscii);" << endl; + out << "\t\t[id(DISPID_KEYUP)] void KeyUp(short* KeyCode, short Shift);" << endl; + out << "\t\t[id(DISPID_MOUSEDOWN)] void MouseDown(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);" << endl; + out << "\t\t[id(DISPID_MOUSEMOVE)] void MouseMove(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);" << endl; + out << "\t\t[id(DISPID_MOUSEUP)] void MouseUp(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);" << endl << endl; + } + + for (i = methodoff; i < mo->methodCount(); ++i) { + const QMetaMethod signal = mo->method(i); + if (signal.methodType() != QMetaMethod::Signal) + continue; + + QByteArray signature(signal.signature()); + QByteArray name(signature.left(signature.indexOf('('))); + signature = signature.mid(name.length() + 1); + signature.truncate(signature.length() - 1); + + QList<QByteArray> parameterTypes(signal.parameterTypes()); + QList<QByteArray> parameterNames(signal.parameterNames()); + + bool isDefault = defSignal == QLatin1String(name); + name = renameOverloads(replaceKeyword(name)); + bool ok = true; + + QByteArray type = signal.typeName(); + if (!type.isEmpty()) // signals with return value not supported + continue; + + QByteArray ptype(prototype(parameterTypes, parameterNames, &ok)); + if (!ok) + out << "\t/****** Signal parameter uses unsupported datatype" << endl; + + out << "\t\t[id(" << id << ')'; + if (isDefault) + out << ", uidefault"; + out << "] void " << name << '(' << ptype << ");" << endl; + + if (!ok) + out << "\t******/" << endl; + ++id; + } + out << "\t};" << endl << endl; + } + + out << "\t[" << endl; + + if (qstricmp(mo->classInfo(mo->indexOfClassInfo("Aggregatable")).value(), "no")) + out << "\t\taggregatable," << endl; + if (!qstricmp(mo->classInfo(mo->indexOfClassInfo("RegisterObject")).value(), "yes")) + out << "\t\tappobject," << endl; + if (mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value()) + out << "\t\tlicensed," << endl; + const char *helpString = mo->classInfo(mo->indexOfClassInfo("Description")).value(); + if (helpString) + out << "\t\thelpstring(\"" << helpString << "\")," << endl; + else + out << "\t\thelpstring(\"" << cleanClassName << " Class\")," << endl; + const char *classVersion = mo->classInfo(mo->indexOfClassInfo("Version")).value(); + if (classVersion) + out << "\t\tversion(" << classVersion << ")," << endl; + out << "\t\tuuid(" << classID << ')'; + if (control) { + out << ", " << endl; + out << "\t\tcontrol"; + } else if (!o) { + out << ", " << endl; + out << "\t\tnoncreatable"; + } + out << endl; + out << "\t]" << endl; + out << "\tcoclass " << cleanClassName << endl; + out << "\t{" << endl; + out << "\t\t[default] dispinterface I" << cleanClassName << ';' << endl; + if (hasEvents) + out << "\t\t[default, source] dispinterface I" << cleanClassName << "Events;" << endl; + out << "\t};" << endl; + + return S_OK; +} + +#if defined(Q_CC_BOR) +extern "C" __stdcall HRESULT DumpIDL(const QString &outfile, const QString &ver) +#else +extern "C" HRESULT __stdcall DumpIDL(const QString &outfile, const QString &ver) +#endif +{ + qAxIsServer = false; + QTextStream out; + if (outfile.contains(QLatin1String("\\"))) { + QString outpath = outfile.left(outfile.lastIndexOf(QLatin1String("\\"))); + QDir dir; + dir.mkpath(outpath); + } + QFile file(outfile); + file.remove(); + + QString filebase = QString::fromWCharArray(qAxModuleFilename); + filebase = filebase.left(filebase.lastIndexOf(QLatin1Char('.'))); + + QString appID = qAxFactory()->appID().toString().toUpper(); + if (QUuid(appID).isNull()) + return 1; + STRIPCB(appID); + QString typeLibID = qAxFactory()->typeLibID().toString().toUpper(); + if (QUuid(typeLibID).isNull()) + return 2; + STRIPCB(typeLibID); + QString typelib = filebase.right(filebase.length() - filebase.lastIndexOf(QLatin1String("\\"))-1); + + if (!file.open(QIODevice::WriteOnly)) + return -1; + + out.setDevice(&file); + + QString version(ver.unicode(), ver.length()); + while (version.count(QLatin1Char('.')) > 1) { + int lastdot = version.lastIndexOf(QLatin1Char('.')); + version = version.left(lastdot) + version.right(version.length() - lastdot - 1); + } + if (version.isEmpty()) + version = QLatin1String("1.0"); + + QString idQRect(QUuid(CLSID_QRect).toString()); + STRIPCB(idQRect); + QString idQSize(QUuid(CLSID_QSize).toString()); + STRIPCB(idQSize); + QString idQPoint(QUuid(CLSID_QPoint).toString()); + STRIPCB(idQPoint); + + out << "/****************************************************************************" << endl; + out << "** Interface definition generated for ActiveQt project" << endl; + out << "**" << endl; + out << "** '" << QString::fromWCharArray(qAxModuleFilename) << '\'' << endl; + out << "**" << endl; + out << "** Created: " << QDateTime::currentDateTime().toString() << endl; + out << "**" << endl; + out << "** WARNING! All changes made in this file will be lost!" << endl; + out << "****************************************************************************/" << endl << endl; + + out << "import \"ocidl.idl\";" << endl; + out << "#include <olectl.h>" << endl << endl; + + // dummy application to create widgets + bool delete_qApp = false; + if (!qApp) { + int argc; + (void)new QApplication(argc, 0); + delete_qApp = true; + } + + out << '[' << endl; + out << "\tuuid(" << typeLibID << ")," << endl; + out << "\tversion(" << version << ")," << endl; + out << "\thelpstring(\"" << typelib << ' ' << version << " Type Library\")" << endl; + out << ']' << endl; + out << "library " << typelib << "Lib" << endl; + out << '{' << endl; + out << "\timportlib(\"stdole32.tlb\");" << endl; + out << "\timportlib(\"stdole2.tlb\");" << endl << endl; + + QStringList keys = qAxFactory()->featureList(); + QStringList::ConstIterator key; + + out << "\t/************************************************************************" << endl; + out << "\t** If this causes a compile error in MIDL you need to upgrade the" << endl; + out << "\t** Platform SDK you are using. Download the SDK from msdn.microsoft.com" << endl; + out << "\t** and make sure that both the system and the Visual Studio environment" << endl; + out << "\t** use the correct files." << endl; + out << "\t**" << endl; + +#ifndef Q_CC_BOR +#if __REQUIRED_RPCNDR_H_VERSION__ < Q_REQUIRED_RPCNDR_H_VERSION + out << "\t** Required version of MIDL could not be verified. QRect, QSize and QPoint" << endl; + out << "\t** support needs an updated Platform SDK to be installed." << endl; + out << "\t*************************************************************************" << endl; +#else + out << "\t************************************************************************/" << endl; +#endif + + out << endl; + out << "\t[uuid(" << idQRect << ")]" << endl; + out << "\tstruct QRect {" << endl; + out << "\t\tint left;" << endl; + out << "\t\tint top;" << endl; + out << "\t\tint right;" << endl; + out << "\t\tint bottom;" << endl; + out << "\t};" << endl << endl; + + out << "\t[uuid(" << idQSize << ")]" << endl; + out << "\tstruct QSize {" << endl; + out << "\t\tint width;" << endl; + out << "\t\tint height;" << endl; + out << "\t};" << endl << endl; + + out << "\t[uuid(" << idQPoint << ")]" << endl; + out << "\tstruct QPoint {" << endl; + out << "\t\tint x;" << endl; + out << "\t\tint y;" << endl; + out << "\t};" << endl; +#if __REQUIRED_RPCNDR_H_VERSION__ < Q_REQUIRED_RPCNDR_H_VERSION + out << "\t*/" << endl; +#endif +#else + out << "\t** Custom data types not supported with Borland." << endl; + out << "\t*************************************************************************" << endl; +#endif + out << endl; + + out << "\t/* Forward declaration of classes that might be used as parameters */" << endl << endl; + + int res = S_OK; + for (key = keys.begin(); key != keys.end(); ++key) { + QByteArray className = (*key).toLatin1(); + const QMetaObject *mo = qAxFactory()->metaObject(QString::fromLatin1(className.constData())); + // We have meta object information for this type. Forward declare it. + if (mo) { + QByteArray cleanType = qax_clean_type(*key, mo).toLatin1(); + out << "\tcoclass " << cleanType << ';' << endl; + subtypes.append(cleanType); + qRegisterMetaType(cleanType, (void**)0); + cleanType += '*'; + subtypes.append(cleanType); + qRegisterMetaType(cleanType, (void**)0); + } + } + out << endl; + + for (key = keys.begin(); key != keys.end(); ++key) { + QByteArray className = (*key).toLatin1(); + const QMetaObject *mo = qAxFactory()->metaObject(QString::fromLatin1(className.constData())); + // We have meta object information for this type. Define it. + if (mo) { + QObject *o = qAxFactory()->createObject(QString::fromLatin1(className.constData())); + // It's not a control class, so it is actually a subtype. Define it. + if (!o) + res = classIDL(0, mo, QString::fromLatin1(className), false, out); + delete o; + } + } + + out << endl; + if (res != S_OK) + goto ErrorInClass; + + for (key = keys.begin(); key != keys.end(); ++key) { + QByteArray className = (*key).toLatin1(); + QObject *o = qAxFactory()->createObject(QString::fromLatin1(className.constData())); + if (!o) + continue; + const QMetaObject *mo = o->metaObject(); + QAxBindable *bind = (QAxBindable*)o->qt_metacast("QAxBindable"); + bool isBindable = bind != 0; + + QByteArray cleanType = qax_clean_type(*key, mo).toLatin1(); + subtypes.append(cleanType); + subtypes.append(cleanType + '*'); + res = classIDL(o, mo, QString::fromLatin1(className.constData()), isBindable, out); + delete o; + if (res != S_OK) + break; + } + + out << "};" << endl; + out.flush(); + +ErrorInClass: + if (delete_qApp) + delete qApp; + + if (res != S_OK) { + file.close(); + file.remove(); + } + + return res; +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/control/qaxserver.def b/src/activeqt/control/qaxserver.def new file mode 100644 index 0000000..a00638d --- /dev/null +++ b/src/activeqt/control/qaxserver.def @@ -0,0 +1,8 @@ +; mfc_test.def : Declares the module parameters. + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DumpIDL PRIVATE diff --git a/src/activeqt/control/qaxserver.ico b/src/activeqt/control/qaxserver.ico Binary files differnew file mode 100644 index 0000000..c80d36a --- /dev/null +++ b/src/activeqt/control/qaxserver.ico diff --git a/src/activeqt/control/qaxserver.rc b/src/activeqt/control/qaxserver.rc new file mode 100644 index 0000000..390e481 --- /dev/null +++ b/src/activeqt/control/qaxserver.rc @@ -0,0 +1,2 @@ +1 TYPELIB "qaxserver.rc" +1 ICON DISCARDABLE "qaxserver.ico" diff --git a/src/activeqt/control/qaxserverbase.cpp b/src/activeqt/control/qaxserverbase.cpp new file mode 100644 index 0000000..a2f9579 --- /dev/null +++ b/src/activeqt/control/qaxserverbase.cpp @@ -0,0 +1,4444 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define QT_NO_CAST_TO_ASCII + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qabstracteventdispatcher.h> +#include <qapplication.h> +#include <qbuffer.h> +#include <qdatastream.h> +#include <qdebug.h> +#include <qevent.h> +#include <qeventloop.h> +#include <qfile.h> +#include <qpointer.h> +#include <qhash.h> +#include <qmap.h> +#include <qmenubar.h> +#include <qmenu.h> +#include <qmetaobject.h> +#include <qpixmap.h> +#include <qstatusbar.h> +#include <qwhatsthis.h> +#include <ocidl.h> +#include <olectl.h> +#include <private/qcoreapplication_p.h> + +#include "qaxfactory.h" +#include "qaxbindable.h" +#include "qaxaggregated.h" + +#include "../shared/qaxtypes.h" + +#if defined Q_CC_GNU +# include <w32api.h> +#endif + +#ifndef Q_OS_WIN64 +#define ULONG_PTR DWORD +#endif + +QT_BEGIN_NAMESPACE + +extern HHOOK qax_hhook; + +// in qaxserver.cpp +extern ITypeLib *qAxTypeLibrary; +extern QAxFactory *qAxFactory(); +extern unsigned long qAxLock(); +extern unsigned long qAxUnlock(); +extern HANDLE qAxInstance; +extern bool qAxOutProcServer; + +static int invokeCount = 0; + +#ifdef QT_DEBUG +unsigned long qaxserverbase_instance_count = 0; +#endif + +// in qaxserverdll.cpp +extern bool qax_ownQApp; + +struct QAxExceptInfo +{ + QAxExceptInfo(int c, const QString &s, const QString &d, const QString &x) + : code(c), src(s), desc(d), context(x) + { + } + int code; + QString src; + QString desc; + QString context; +}; + + +bool qt_sendSpontaneousEvent(QObject*, QEvent*); + +/* + \class QAxServerBase + \brief The QAxServerBase class is an ActiveX control hosting a QWidget. + + \internal +*/ +class QAxServerBase : + public QObject, + public IAxServerBase, + public IDispatch, + public IOleObject, + public IOleControl, +#if defined Q_CC_GNU +# if (__W32API_MAJOR_VERSION < 2 || (__W32API_MAJOR_VERSION == 2 && __W32API_MINOR_VERSION < 5)) + public IViewObject, // this should not be needed as IViewObject2 is meant to inherit from this, + // untill the mingw headers are fixed this will need to stay. +# endif +#endif + public IViewObject2, + public IOleInPlaceObject, + public IOleInPlaceActiveObject, + public IProvideClassInfo2, + public IConnectionPointContainer, + public IPersistStream, + public IPersistStreamInit, + public IPersistStorage, + public IPersistPropertyBag, + public IPersistFile, + public IDataObject +{ +public: + typedef QMap<QUuid,IConnectionPoint*> ConnectionPoints; + typedef QMap<QUuid,IConnectionPoint*>::Iterator ConnectionPointsIterator; + + QAxServerBase(const QString &classname, IUnknown *outerUnknown); + QAxServerBase(QObject *o); + + void init(); + + ~QAxServerBase(); + +// Window creation + HWND create(HWND hWndParent, RECT& rcPos); + HMENU createPopup(QMenu *popup, HMENU oldMenu = 0); + void createMenu(QMenuBar *menuBar); + void removeMenu(); + + static LRESULT QT_WIN_CALLBACK ActiveXProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +// Object registration with OLE + void registerActiveObject(IUnknown *object); + void revokeActiveObject(); + +// IUnknown + unsigned long WINAPI AddRef() + { + if (m_outerUnknown) + return m_outerUnknown->AddRef(); + + EnterCriticalSection(&refCountSection); + unsigned long r = ++ref; + LeaveCriticalSection(&refCountSection); + + return r; + } + unsigned long WINAPI Release() + { + if (m_outerUnknown) + return m_outerUnknown->Release(); + + EnterCriticalSection(&refCountSection); + unsigned long r = --ref; + LeaveCriticalSection(&refCountSection); + + if (!r) { + delete this; + return 0; + } + return r; + } + HRESULT WINAPI QueryInterface(REFIID iid, void **iface); + HRESULT InternalQueryInterface(REFIID iid, void **iface); + +// IAxServerBase + IUnknown *clientSite() const + { + return m_spClientSite; + } + + void emitPropertyChanged(const char*); + bool emitRequestPropertyChange(const char*); + QObject *qObject() const + { + return theObject; + } + void ensureMetaData(); + bool isPropertyExposed(int index); + + void reportError(int code, const QString &src, const QString &desc, const QString &context) + { + if (exception) + delete exception; + exception = new QAxExceptInfo(code, src, desc, context); + } + +// IDispatch + STDMETHOD(GetTypeInfoCount)(UINT* pctinfo); + STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo); + STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid); + STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, + EXCEPINFO* pexcepinfo, UINT* puArgErr); + +// IProvideClassInfo + STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo); + +// IProvideClassInfo2 + STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID); + +// IOleObject + STDMETHOD(Advise)(IAdviseSink* pAdvSink, DWORD* pdwConnection); + STDMETHOD(Close)(DWORD dwSaveOption); + STDMETHOD(DoVerb)(LONG iVerb, LPMSG lpmsg, IOleClientSite* pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect); + STDMETHOD(EnumAdvise)(IEnumSTATDATA** ppenumAdvise); + STDMETHOD(EnumVerbs)(IEnumOLEVERB** ppEnumOleVerb); + STDMETHOD(GetClientSite)(IOleClientSite** ppClientSite); + STDMETHOD(GetClipboardData)(DWORD dwReserved, IDataObject** ppDataObject); + STDMETHOD(GetExtent)(DWORD dwDrawAspect, SIZEL* psizel); + STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD *pdwStatus); + STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk); + STDMETHOD(GetUserClassID)(CLSID* pClsid); + STDMETHOD(GetUserType)(DWORD dwFormOfType, LPOLESTR *pszUserType); + STDMETHOD(InitFromData)(IDataObject* pDataObject, BOOL fCreation, DWORD dwReserved); + STDMETHOD(IsUpToDate)(); + STDMETHOD(SetClientSite)(IOleClientSite* pClientSite); + STDMETHOD(SetColorScheme)(LOGPALETTE* pLogPal); + STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel); + STDMETHOD(SetHostNames)(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj); + STDMETHOD(SetMoniker)(DWORD dwWhichMoniker, IMoniker* ppmk); + STDMETHOD(Unadvise)(DWORD dwConnection); + STDMETHOD(Update)(); + +// IViewObject + STDMETHOD(Draw)(DWORD dwAspect, LONG lIndex, void *pvAspect, DVTARGETDEVICE *ptd, + HDC hicTargetDevice, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, + BOOL(__stdcall*pfnContinue)(ULONG_PTR), ULONG_PTR dwContinue); + STDMETHOD(GetColorSet)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, + HDC hicTargetDev, LOGPALETTE **ppColorSet); + STDMETHOD(Freeze)(DWORD dwAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze); + STDMETHOD(Unfreeze)(DWORD dwFreeze); + STDMETHOD(SetAdvise)(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink); + STDMETHOD(GetAdvise)(DWORD *aspects, DWORD *advf, IAdviseSink **pAdvSink); + +// IViewObject2 + STDMETHOD(GetExtent)(DWORD dwAspect, LONG lindex, DVTARGETDEVICE *ptd, LPSIZEL lpsizel); + +// IOleControl + STDMETHOD(FreezeEvents)(BOOL); + STDMETHOD(GetControlInfo)(LPCONTROLINFO); + STDMETHOD(OnAmbientPropertyChange)(DISPID); + STDMETHOD(OnMnemonic)(LPMSG); + +// IOleWindow + STDMETHOD(GetWindow)(HWND *pHwnd); + STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode); + +// IOleInPlaceObject + STDMETHOD(InPlaceDeactivate)(); + STDMETHOD(UIDeactivate)(); + STDMETHOD(SetObjectRects)(LPCRECT lprcPosRect, LPCRECT lprcClipRect); + STDMETHOD(ReactivateAndUndo)(); + +// IOleInPlaceActiveObject + STDMETHOD(TranslateAcceleratorW)(MSG *pMsg); + STDMETHOD(TranslateAcceleratorA)(MSG *pMsg); + STDMETHOD(OnFrameWindowActivate)(BOOL); + STDMETHOD(OnDocWindowActivate)(BOOL fActivate); + STDMETHOD(ResizeBorder)(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow); + STDMETHOD(EnableModeless)(BOOL); + +// IConnectionPointContainer + STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints**); + STDMETHOD(FindConnectionPoint)(REFIID, IConnectionPoint**); + +// IPersist + STDMETHOD(GetClassID)(GUID*clsid) + { + *clsid = qAxFactory()->classID(class_name); + return S_OK; + } + +// IPersistStreamInit + STDMETHOD(InitNew)(VOID); + STDMETHOD(IsDirty)(); + STDMETHOD(Load)(IStream *pStm); + STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize); + +// IPersistPropertyBag + STDMETHOD(Load)(IPropertyBag *, IErrorLog *); + STDMETHOD(Save)(IPropertyBag *, BOOL, BOOL); + +// IPersistStorage + STDMETHOD(InitNew)(IStorage *pStg); + STDMETHOD(Load)(IStorage *pStg); + STDMETHOD(Save)(IStorage *pStg, BOOL fSameAsLoad); + STDMETHOD(SaveCompleted)(IStorage *pStgNew); + STDMETHOD(HandsOffStorage)(); + +// IPersistFile + STDMETHOD(SaveCompleted)(LPCOLESTR fileName); + STDMETHOD(GetCurFile)(LPOLESTR *currentFile); + STDMETHOD(Load)(LPCOLESTR fileName, DWORD mode); + STDMETHOD(Save)(LPCOLESTR fileName, BOOL fRemember); + +// IDataObject + STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium); + STDMETHOD(GetDataHere)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */); + STDMETHOD(QueryGetData)(FORMATETC* /* pformatetc */); + STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */); + STDMETHOD(SetData)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */); + STDMETHOD(EnumFormatEtc)(DWORD /* dwDirection */, IEnumFORMATETC** /* ppenumFormatEtc */); + STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection); + STDMETHOD(DUnadvise)(DWORD dwConnection); + STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise); + +// QObject + int qt_metacall(QMetaObject::Call, int index, void **argv); + + bool eventFilter(QObject *o, QEvent *e); +private: + void update(); + void resize(const QSize &newSize); + void updateGeometry(); + void updateMask(); + bool internalCreate(); + void internalBind(); + void internalConnect(); + HRESULT internalActivate(); + + friend class QAxBindable; + friend class QAxPropertyPage; + + QAxAggregated *aggregatedObject; + ConnectionPoints points; + + union { + QWidget *widget; + QObject *object; + } qt; + QPointer<QObject> theObject; + unsigned isWidget :1; + unsigned ownObject :1; + unsigned initNewCalled :1; + unsigned dirtyflag :1; + unsigned hasStockEvents :1; + unsigned stayTopLevel :1; + unsigned isInPlaceActive :1; + unsigned isUIActive :1; + unsigned wasUIActive :1; + unsigned inDesignMode :1; + unsigned canTakeFocus :1; + short freezeEvents; + + HWND m_hWnd; + + HMENU hmenuShared; + HOLEMENU holemenu; + HWND hwndMenuOwner; + QMap<HMENU, QMenu*> menuMap; + QMap<UINT, QAction*> actionMap; + QPointer<QMenuBar> menuBar; + QPointer<QStatusBar> statusBar; + QPointer<QMenu> currentPopup; + QAxExceptInfo *exception; + + CRITICAL_SECTION refCountSection; + CRITICAL_SECTION createWindowSection; + + unsigned long ref; + unsigned long ole_ref; + + QString class_name; + QString currentFileName; + + QHash<long, int> indexCache; + QHash<int,DISPID> signalCache; + + IUnknown *m_outerUnknown; + IAdviseSink *m_spAdviseSink; + QList<STATDATA> adviseSinks; + IOleClientSite *m_spClientSite; + IOleInPlaceSiteWindowless *m_spInPlaceSite; + IOleInPlaceFrame *m_spInPlaceFrame; + ITypeInfo *m_spTypeInfo; + IStorage *m_spStorage; + QSize m_currentExtent; +}; + +class QAxServerAggregate : public IUnknown +{ +public: + QAxServerAggregate(const QString &className, IUnknown *outerUnknown) + : m_outerUnknown(outerUnknown), ref(0) + { + object = new QAxServerBase(className, outerUnknown); + object->registerActiveObject(this); + + InitializeCriticalSection(&refCountSection); + InitializeCriticalSection(&createWindowSection); + } + ~QAxServerAggregate() + { + DeleteCriticalSection(&refCountSection); + DeleteCriticalSection(&createWindowSection); + + delete object; + } + +// IUnknown + unsigned long WINAPI AddRef() + { + EnterCriticalSection(&refCountSection); + unsigned long r = ++ref; + LeaveCriticalSection(&refCountSection); + + return r; + } + unsigned long WINAPI Release() + { + EnterCriticalSection(&refCountSection); + unsigned long r = --ref; + LeaveCriticalSection(&refCountSection); + + if (!r) { + delete this; + return 0; + } + return r; + } + HRESULT WINAPI QueryInterface(REFIID iid, void **iface) + { + *iface = 0; + + HRESULT res = E_NOINTERFACE; + if (iid == IID_IUnknown) { + *iface = (IUnknown*)this; + AddRef(); + return S_OK; + } + return object->InternalQueryInterface(iid, iface); + } + +private: + QAxServerBase *object; + IUnknown *m_outerUnknown; + unsigned long ref; + + CRITICAL_SECTION refCountSection; + CRITICAL_SECTION createWindowSection; +}; + +bool QAxFactory::createObjectWrapper(QObject *object, IDispatch **wrapper) +{ + *wrapper = 0; + QAxServerBase *obj = new QAxServerBase(object); + obj->QueryInterface(IID_IDispatch, (void**)wrapper); + if (*wrapper) + return true; + + delete obj; + return false; +} + + +/* + Helper class to enumerate all supported event interfaces. +*/ +class QAxSignalVec : public IEnumConnectionPoints +{ +public: + QAxSignalVec(const QAxServerBase::ConnectionPoints &points) + : cpoints(points), ref(0) + { + InitializeCriticalSection(&refCountSection); + for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i) + (*i)->AddRef(); + } + QAxSignalVec(const QAxSignalVec &old) + { + InitializeCriticalSection(&refCountSection); + ref = 0; + cpoints = old.cpoints; + for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i) + (*i)->AddRef(); + it = old.it; + } + ~QAxSignalVec() + { + for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i) + (*i)->Release(); + + DeleteCriticalSection(&refCountSection); + } + + unsigned long __stdcall AddRef() + { + EnterCriticalSection(&refCountSection); + unsigned long r = ++ref; + LeaveCriticalSection(&refCountSection); + return ++r; + } + unsigned long __stdcall Release() + { + EnterCriticalSection(&refCountSection); + unsigned long r = --ref; + LeaveCriticalSection(&refCountSection); + + if (!r) { + delete this; + return 0; + } + return r; + } + STDMETHOD(QueryInterface)(REFIID iid, void **iface) + { + *iface = 0; + if (iid == IID_IUnknown) + *iface = this; + else if (iid == IID_IEnumConnectionPoints) + *iface = this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; + } + STDMETHOD(Next)(ULONG cConnections, IConnectionPoint **cpoint, ULONG *pcFetched) + { + unsigned long i; + for (i = 0; i < cConnections; i++) { + if (it == cpoints.end()) + break; + IConnectionPoint *cp = *it; + cp->AddRef(); + cpoint[i] = cp; + ++it; + } + *pcFetched = i; + return i == cConnections ? S_OK : S_FALSE; + } + STDMETHOD(Skip)(ULONG cConnections) + { + while (cConnections) { + ++it; + --cConnections; + if (it == cpoints.end()) + return S_FALSE; + } + return S_OK; + } + STDMETHOD(Reset)() + { + it = cpoints.begin(); + + return S_OK; + } + STDMETHOD(Clone)(IEnumConnectionPoints **ppEnum) + { + *ppEnum = new QAxSignalVec(*this); + (*ppEnum)->AddRef(); + + return S_OK; + } + + QAxServerBase::ConnectionPoints cpoints; + QAxServerBase::ConnectionPointsIterator it; + +private: + CRITICAL_SECTION refCountSection; + + unsigned long ref; +}; + +/* + Helper class to store and enumerate all connected event listeners. +*/ +class QAxConnection : public IConnectionPoint, + public IEnumConnections +{ +public: + typedef QList<CONNECTDATA> Connections; + typedef QList<CONNECTDATA>::Iterator Iterator; + + QAxConnection(QAxServerBase *parent, const QUuid &uuid) + : that(parent), iid(uuid), ref(1) + { + InitializeCriticalSection(&refCountSection); + } + QAxConnection(const QAxConnection &old) + { + InitializeCriticalSection(&refCountSection); + ref = 0; + connections = old.connections; + it = old.it; + that = old.that; + iid = old.iid; + QList<CONNECTDATA>::Iterator it = connections.begin(); + while (it != connections.end()) { + CONNECTDATA connection = *it; + ++it; + connection.pUnk->AddRef(); + } + } + ~QAxConnection() + { + DeleteCriticalSection(&refCountSection); + } + + unsigned long __stdcall AddRef() + { + EnterCriticalSection(&refCountSection); + unsigned long r = ++ref; + LeaveCriticalSection(&refCountSection); + return r; + } + unsigned long __stdcall Release() + { + EnterCriticalSection(&refCountSection); + unsigned long r = --ref; + LeaveCriticalSection(&refCountSection); + + if (!r) { + delete this; + return 0; + } + return r; + } + STDMETHOD(QueryInterface)(REFIID iid, void **iface) + { + *iface = 0; + if (iid == IID_IUnknown) + *iface = (IConnectionPoint*)this; + else if (iid == IID_IConnectionPoint) + *iface = this; + else if (iid == IID_IEnumConnections) + *iface = this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; + } + STDMETHOD(GetConnectionInterface)(IID *pIID) + { + *pIID = iid; + return S_OK; + } + STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC) + { + return that->QueryInterface(IID_IConnectionPointContainer, (void**)ppCPC); + } + STDMETHOD(Advise)(IUnknown*pUnk, DWORD *pdwCookie) + { + { + IDispatch *checkImpl = 0; + pUnk->QueryInterface(iid, (void**)&checkImpl); + if (!checkImpl) + return CONNECT_E_CANNOTCONNECT; + checkImpl->Release(); + } + + CONNECTDATA cd; + cd.dwCookie = connections.count()+1; + cd.pUnk = pUnk; + cd.pUnk->AddRef(); + connections.append(cd); + + *pdwCookie = cd.dwCookie; + return S_OK; + } + STDMETHOD(Unadvise)(DWORD dwCookie) + { + QList<CONNECTDATA>::Iterator it = connections.begin(); + while (it != connections.end()) { + CONNECTDATA cd = *it; + if (cd.dwCookie == dwCookie) { + cd.pUnk->Release(); + connections.erase(it); + return S_OK; + } + ++it; + } + return CONNECT_E_NOCONNECTION; + } + STDMETHOD(EnumConnections)(IEnumConnections **ppEnum) + { + *ppEnum = this; + AddRef(); + + return S_OK; + } + STDMETHOD(Next)(ULONG cConnections, CONNECTDATA *cd, ULONG *pcFetched) + { + unsigned long i; + for (i = 0; i < cConnections; i++) { + if (it == connections.end()) + break; + cd[i] = *it; + cd[i].pUnk->AddRef(); + ++it; + } + if (pcFetched) + *pcFetched = i; + return i == cConnections ? S_OK : S_FALSE; + } + STDMETHOD(Skip)(ULONG cConnections) + { + while (cConnections) { + ++it; + --cConnections; + if (it == connections.end()) + return S_FALSE; + } + return S_OK; + } + STDMETHOD(Reset)() + { + it = connections.begin(); + + return S_OK; + } + STDMETHOD(Clone)(IEnumConnections **ppEnum) + { + *ppEnum = new QAxConnection(*this); + (*ppEnum)->AddRef(); + + return S_OK; + } + +private: + QAxServerBase *that; + QUuid iid; + Connections connections; + Iterator it; + + CRITICAL_SECTION refCountSection; + unsigned long ref; +}; + +// callback for DLL server to hook into non-Qt eventloop +LRESULT QT_WIN_CALLBACK axs_FilterProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (qApp && !invokeCount) + qApp->sendPostedEvents(); + + return CallNextHookEx(qax_hhook, nCode, wParam, lParam); +} + +// filter for executable case to hook into Qt eventloop +// for DLLs the client calls TranslateAccelerator +bool qax_winEventFilter(void *message) +{ + MSG *pMsg = (MSG*)message; + if (pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) + return false; + + bool ret = false; + QWidget *aqt = QWidget::find(pMsg->hwnd); + if (!aqt) + return ret; + + HWND baseHwnd = ::GetParent(aqt->winId()); + QAxServerBase *axbase = 0; + while (!axbase && baseHwnd) { +#ifdef GWLP_USERDATA + axbase = (QAxServerBase*)GetWindowLongPtr(baseHwnd, GWLP_USERDATA); +#else + axbase = (QAxServerBase*)GetWindowLong(baseHwnd, GWL_USERDATA); +#endif + + baseHwnd = ::GetParent(baseHwnd); + } + if (!axbase) + return ret; + + HRESULT hres = axbase->TranslateAcceleratorW(pMsg); + return hres == S_OK; +} + +extern void qWinMsgHandler(QtMsgType t, const char* str); + +// COM Factory class, mapping COM requests to ActiveQt requests. +// One instance of this class for each ActiveX the server can provide. +class QClassFactory : public IClassFactory2 +{ +public: + QClassFactory(CLSID clsid) + : ref(0), licensed(false) + { + InitializeCriticalSection(&refCountSection); + + // COM only knows the CLSID, but QAxFactory is class name based... + QStringList keys = qAxFactory()->featureList(); + for (QStringList::Iterator key = keys.begin(); key != keys.end(); ++key) { + if (qAxFactory()->classID(*key) == clsid) { + className = *key; + break; + } + } + + const QMetaObject *mo = qAxFactory()->metaObject(className); + if (mo) { + classKey = QLatin1String(mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value()); + licensed = !classKey.isEmpty(); + } + } + + ~QClassFactory() + { + DeleteCriticalSection(&refCountSection); + } + + // IUnknown + unsigned long WINAPI AddRef() + { + EnterCriticalSection(&refCountSection); + unsigned long r = ++ref; + LeaveCriticalSection(&refCountSection); + return ++r; + } + unsigned long WINAPI Release() + { + EnterCriticalSection(&refCountSection); + unsigned long r = --ref; + LeaveCriticalSection(&refCountSection); + + if (!r) { + delete this; + return 0; + } + return r; + } + HRESULT WINAPI QueryInterface(REFIID iid, LPVOID *iface) + { + *iface = 0; + if (iid == IID_IUnknown) + *iface = (IUnknown*)this; + else if (iid == IID_IClassFactory) + *iface = (IClassFactory*)this; + else if (iid == IID_IClassFactory2 && licensed) + *iface = (IClassFactory2*)this; + else + return E_NOINTERFACE; + + AddRef(); + return S_OK; + } + + HRESULT WINAPI CreateInstanceHelper(IUnknown *pUnkOuter, REFIID iid, void **ppObject) + { + if (pUnkOuter) { + if (iid != IID_IUnknown) + return CLASS_E_NOAGGREGATION; + const QMetaObject *mo = qAxFactory()->metaObject(className); + if (mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Aggregatable")).value(), "no")) + return CLASS_E_NOAGGREGATION; + } + + // Make sure a QApplication instance is present (inprocess case) + if (!qApp) { + qInstallMsgHandler(qWinMsgHandler); + qax_ownQApp = true; + int argc = 0; + QApplication *app = new QApplication(argc, 0); + } + qApp->setQuitOnLastWindowClosed(false); + + if (qAxOutProcServer) + QAbstractEventDispatcher::instance()->setEventFilter(qax_winEventFilter); + else + QApplication::instance()->d_func()->in_exec = true; + + // hook into eventloop; this allows a server to create his own QApplication object + if (!qax_hhook && qax_ownQApp) { + qax_hhook = SetWindowsHookEx(WH_GETMESSAGE, axs_FilterProc, 0, GetCurrentThreadId()); + } + + HRESULT res; + // Create the ActiveX wrapper - aggregate if requested + if (pUnkOuter) { + QAxServerAggregate *aggregate = new QAxServerAggregate(className, pUnkOuter); + res = aggregate->QueryInterface(iid, ppObject); + if (FAILED(res)) + delete aggregate; + } else { + QAxServerBase *activeqt = new QAxServerBase(className, pUnkOuter); + res = activeqt->QueryInterface(iid, ppObject); + if (FAILED(res)) + delete activeqt; + else + activeqt->registerActiveObject((IUnknown*)(IDispatch*)activeqt); + } + return res; + } + + // IClassFactory + HRESULT WINAPI CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppObject) + { + // class is licensed + if (licensed && !qAxFactory()->validateLicenseKey(className, QString())) + return CLASS_E_NOTLICENSED; + + return CreateInstanceHelper(pUnkOuter, iid, ppObject); + } + HRESULT WINAPI LockServer(BOOL fLock) + { + if (fLock) + qAxLock(); + else + qAxUnlock(); + + return S_OK; + } + + // IClassFactory2 + HRESULT WINAPI RequestLicKey(DWORD, BSTR *pKey) + { + if (!pKey) + return E_POINTER; + *pKey = 0; + + // This of course works only on fully licensed machines + if (!qAxFactory()->validateLicenseKey(className, QString())) + return CLASS_E_NOTLICENSED; + + *pKey = QStringToBSTR(classKey); + return S_OK; + } + + HRESULT WINAPI GetLicInfo(LICINFO *pLicInfo) + { + if (!pLicInfo) + return E_POINTER; + pLicInfo->cbLicInfo = sizeof(LICINFO); + + // class specific license key? + const QMetaObject *mo = qAxFactory()->metaObject(className); + const char *key = mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value(); + pLicInfo->fRuntimeKeyAvail = key && key[0]; + + // machine fully licensed? + pLicInfo->fLicVerified = qAxFactory()->validateLicenseKey(className, QString()); + + return S_OK; + } + + HRESULT WINAPI CreateInstanceLic(IUnknown *pUnkOuter, IUnknown *pUnkReserved, REFIID iid, BSTR bKey, PVOID *ppObject) + { + QString licenseKey = QString::fromWCharArray(bKey); + if (!qAxFactory()->validateLicenseKey(className, licenseKey)) + return CLASS_E_NOTLICENSED; + return CreateInstanceHelper(pUnkOuter, iid, ppObject); + } + + QString className; + +protected: + CRITICAL_SECTION refCountSection; + unsigned long ref; + bool licensed; + QString classKey; +}; + +// Create a QClassFactory object for class \a iid +HRESULT GetClassObject(REFIID clsid, REFIID iid, void **ppUnk) +{ + QClassFactory *factory = new QClassFactory(clsid); + if (!factory) + return E_OUTOFMEMORY; + if (factory->className.isEmpty()) { + delete factory; + return E_NOINTERFACE; + } + HRESULT res = factory->QueryInterface(iid, ppUnk); + if (res != S_OK) + delete factory; + return res; +} + + +/*! + Constructs a QAxServerBase object wrapping the QWidget \a + classname into an ActiveX control. + + The constructor is called by the QClassFactory object provided by + the COM server for the respective CLSID. +*/ +QAxServerBase::QAxServerBase(const QString &classname, IUnknown *outerUnknown) +: aggregatedObject(0), ref(0), ole_ref(0), class_name(classname), + m_hWnd(0), hmenuShared(0), hwndMenuOwner(0), + m_outerUnknown(outerUnknown) +{ + init(); + + internalCreate(); +} + +/*! + Constructs a QAxServerBase object wrapping \a o. +*/ +QAxServerBase::QAxServerBase(QObject *o) +: aggregatedObject(0), ref(0), ole_ref(0), + m_hWnd(0), hmenuShared(0), hwndMenuOwner(0), + m_outerUnknown(0) +{ + init(); + + qt.object = o; + if (o) { + theObject = o; + isWidget = false; + class_name = QLatin1String(o->metaObject()->className()); + } + internalBind(); + internalConnect(); +} + +/*! + Initializes data members. +*/ +void QAxServerBase::init() +{ + qt.object = 0; + isWidget = false; + ownObject = false; + initNewCalled = false; + dirtyflag = false; + hasStockEvents = false; + stayTopLevel = false; + isInPlaceActive = false; + isUIActive = false; + wasUIActive = false; + inDesignMode = false; + canTakeFocus = false; + freezeEvents = 0; + exception = 0; + + m_spAdviseSink = 0; + m_spClientSite = 0; + m_spInPlaceSite = 0; + m_spInPlaceFrame = 0; + m_spTypeInfo = 0; + m_spStorage = 0; + + InitializeCriticalSection(&refCountSection); + InitializeCriticalSection(&createWindowSection); + +#ifdef QT_DEBUG + EnterCriticalSection(&refCountSection); + ++qaxserverbase_instance_count; + LeaveCriticalSection(&refCountSection); +#endif + + qAxLock(); + + points[IID_IPropertyNotifySink] = new QAxConnection(this, IID_IPropertyNotifySink); +} + +/*! + Destroys the QAxServerBase object, releasing all allocated + resources and interfaces. +*/ +QAxServerBase::~QAxServerBase() +{ +#ifdef QT_DEBUG + EnterCriticalSection(&refCountSection); + --qaxserverbase_instance_count; + LeaveCriticalSection(&refCountSection); +#endif + + revokeActiveObject(); + + for (QAxServerBase::ConnectionPointsIterator it = points.begin(); it != points.end(); ++it) { + if (it.value()) + (*it)->Release(); + } + delete aggregatedObject; + aggregatedObject = 0; + if (theObject) { + qt.object->disconnect(this); + QObject *aqt = qt.object; + qt.object = 0; + if (ownObject) + delete aqt; + } + + if (m_spAdviseSink) m_spAdviseSink->Release(); + m_spAdviseSink = 0; + for (int i = 0; i < adviseSinks.count(); ++i) { + adviseSinks.at(i).pAdvSink->Release(); + } + if (m_spClientSite) m_spClientSite->Release(); + m_spClientSite = 0; + if (m_spInPlaceFrame) m_spInPlaceFrame->Release(); + m_spInPlaceFrame = 0; + if (m_spInPlaceSite) m_spInPlaceSite->Release(); + m_spInPlaceSite = 0; + if (m_spTypeInfo) m_spTypeInfo->Release(); + m_spTypeInfo = 0; + if (m_spStorage) m_spStorage->Release(); + m_spStorage = 0; + + DeleteCriticalSection(&refCountSection); + DeleteCriticalSection(&createWindowSection); + + qAxUnlock(); +} + +/* + Registering with OLE +*/ +void QAxServerBase::registerActiveObject(IUnknown *object) +{ + if (ole_ref || !qt.object || !qAxOutProcServer) + return; + + const QMetaObject *mo = qt.object->metaObject(); + if (!qstricmp(mo->classInfo(mo->indexOfClassInfo("RegisterObject")).value(), "yes")) + RegisterActiveObject(object, qAxFactory()->classID(class_name), ACTIVEOBJECT_WEAK, &ole_ref); +} + +void QAxServerBase::revokeActiveObject() +{ + if (!ole_ref) + return; + + RevokeActiveObject(ole_ref, 0); + ole_ref = 0; +} + +/* + QueryInterface implementation. +*/ +HRESULT WINAPI QAxServerBase::QueryInterface(REFIID iid, void **iface) +{ + if (m_outerUnknown) + return m_outerUnknown->QueryInterface(iid, iface); + + return InternalQueryInterface(iid, iface); +} + +HRESULT QAxServerBase::InternalQueryInterface(REFIID iid, void **iface) +{ + *iface = 0; + + if (iid == IID_IUnknown) { + *iface = (IUnknown*)(IDispatch*)this; + } else { + HRESULT res = S_OK; + if (aggregatedObject) + res = aggregatedObject->queryInterface(iid, iface); + if (*iface) + return res; + } + + if (!(*iface)) { + if (iid == qAxFactory()->interfaceID(class_name)) + *iface = (IDispatch*)this; + if (iid == IID_IDispatch) + *iface = (IDispatch*)this; + else if (iid == IID_IAxServerBase) + *iface = (IAxServerBase*)this; + else if (iid == IID_IOleObject) + *iface = (IOleObject*)this; + else if (iid == IID_IConnectionPointContainer) + *iface = (IConnectionPointContainer*)this; + else if (iid == IID_IProvideClassInfo) + *iface = (IProvideClassInfo*)this; + else if (iid == IID_IProvideClassInfo2) + *iface = (IProvideClassInfo2*)this; + else if (iid == IID_IPersist) + *iface = (IPersist*)(IPersistStream*)this; + else if (iid == IID_IPersistStream) + *iface = (IPersistStream*)this; + else if (iid == IID_IPersistStreamInit) + *iface = (IPersistStreamInit*)this; + else if (iid == IID_IPersistStorage) + *iface = (IPersistStorage*)this; + else if (iid == IID_IPersistPropertyBag) + *iface = (IPersistPropertyBag*)this; + else if (iid == IID_IPersistFile && + qAxFactory()->metaObject(class_name)->indexOfClassInfo("MIME") != -1) + *iface = (IPersistFile*)this; + else if (iid == IID_IViewObject) + *iface = (IViewObject*)this; + else if (iid == IID_IViewObject2) + *iface = (IViewObject2*)this; + else if (isWidget) { + if (iid == IID_IOleControl) + *iface = (IOleControl*)this; + else if (iid == IID_IOleWindow) + *iface = (IOleWindow*)(IOleInPlaceObject*)this; + else if (iid == IID_IOleInPlaceObject) + *iface = (IOleInPlaceObject*)this; + else if (iid == IID_IOleInPlaceActiveObject) + *iface = (IOleInPlaceActiveObject*)this; + else if (iid == IID_IDataObject) + *iface = (IDataObject*)this; + } + } + if (!*iface) + return E_NOINTERFACE; + + AddRef(); + return S_OK; +} + +/*! + Detects and initilaizes implementation of QAxBindable in objects. +*/ +void QAxServerBase::internalBind() +{ + QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable"); + if (axb) { + // no addref; this is aggregated + axb->activex = this; + if (!aggregatedObject) + aggregatedObject = axb->createAggregate(); + if (aggregatedObject) { + aggregatedObject->controlling_unknown = (IUnknown*)(IDispatch*)this; + aggregatedObject->the_object = qt.object; + } + } +} + +/*! + Connects object signals to event dispatcher. +*/ +void QAxServerBase::internalConnect() +{ + QUuid eventsID = qAxFactory()->eventsID(class_name); + if (!eventsID.isNull()) { + if (!points[eventsID]) + points[eventsID] = new QAxConnection(this, eventsID); + + // connect the generic slot to all signals of qt.object + const QMetaObject *mo = qt.object->metaObject(); + for (int isignal = mo->methodCount()-1; isignal >= 0; --isignal) { + if (mo->method(isignal).methodType() == QMetaMethod::Signal) + QMetaObject::connect(qt.object, isignal, this, isignal); + } + } +} + +/*! + Creates the QWidget for the classname passed to the c'tor. + + All signals of the widget class are connected to the internal event mapper. + If the widget implements QAxBindable, stock events are also connected. +*/ +bool QAxServerBase::internalCreate() +{ + if (qt.object) + return true; + + qt.object = qAxFactory()->createObject(class_name); + Q_ASSERT(qt.object); + if (!qt.object) + return false; + + theObject = qt.object; + ownObject = true; + isWidget = qt.object->isWidgetType(); + hasStockEvents = qAxFactory()->hasStockEvents(class_name); + stayTopLevel = qAxFactory()->stayTopLevel(class_name); + + internalBind(); + if (isWidget) { + if (!stayTopLevel) { + QEvent e(QEvent::EmbeddingControl); + QApplication::sendEvent(qt.widget, &e); + ::SetWindowLong(qt.widget->winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + } + qt.widget->setAttribute(Qt::WA_QuitOnClose, false); + qt.widget->move(0, 0); + + // initialize to sizeHint, but don't set resized flag so that container has a chance to override + bool wasResized = qt.widget->testAttribute(Qt::WA_Resized); + updateGeometry(); + if (!wasResized && qt.widget->testAttribute(Qt::WA_Resized) + && qt.widget->sizePolicy() != QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)) { + qt.widget->setAttribute(Qt::WA_Resized, false); + } + } + + internalConnect(); + // install an event filter for stock events + if (isWidget) { + qt.object->installEventFilter(this); + const QList<QWidget*> children = qt.object->findChildren<QWidget*>(); + QList<QWidget*>::ConstIterator it = children.constBegin(); + while (it != children.constEnd()) { + (*it)->installEventFilter(this); + ++it; + } + } + return true; +} + +/* +class HackMenuData : public QMenuData +{ + friend class QAxServerBase; +}; +*/ + +class HackWidget : public QWidget +{ + friend class QAxServerBase; +}; +/* + Message handler. \a hWnd is always the ActiveX widget hosting the Qt widget. + \a uMsg is handled as follows + \list + \i WM_CREATE The ActiveX control is created + \i WM_DESTROY The QWidget is destroyed + \i WM_SHOWWINDOW The QWidget is parented into the ActiveX window + \i WM_PAINT The QWidget is updated + \i WM_SIZE The QWidget is resized to the new size + \i WM_SETFOCUS and + \i WM_KILLFOCUS The client site is notified about the focus transfer + \i WM_MOUSEACTIVATE The ActiveX is activated + \endlist + + The semantics of \a wParam and \a lParam depend on the value of \a uMsg. +*/ +LRESULT QT_WIN_CALLBACK QAxServerBase::ActiveXProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_CREATE) { + CREATESTRUCT *cs = (CREATESTRUCT*)lParam; + QAxServerBase *that = (QAxServerBase*)cs->lpCreateParams; + +#ifdef GWLP_USERDATA + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)that); +#else + SetWindowLong(hWnd, GWL_USERDATA, (LONG)that); +#endif + + that->m_hWnd = hWnd; + + return ::DefWindowProc(hWnd, uMsg, wParam, lParam); + } + + QAxServerBase *that = 0; + +#ifdef GWLP_USERDATA + that = (QAxServerBase*)GetWindowLongPtr(hWnd, GWLP_USERDATA); +#else + that = (QAxServerBase*)GetWindowLong(hWnd, GWL_USERDATA); +#endif + + if (that) { + int width = that->qt.widget ? that->qt.widget->width() : 0; + int height = that->qt.widget ? that->qt.widget->height() : 0; + RECT rcPos = {0, 0, width + 1, height + 1}; + + switch (uMsg) { + case WM_NCDESTROY: + that->m_hWnd = 0; + break; + + case WM_QUERYENDSESSION: + case WM_DESTROY: + // save the window handle + if (that->qt.widget) { + that->qt.widget->hide(); + ::SetParent(that->qt.widget->winId(), 0); + } + break; + + case WM_SHOWWINDOW: + if(wParam) { + that->internalCreate(); + if (!that->stayTopLevel) { + ::SetParent(that->qt.widget->winId(), that->m_hWnd); + that->qt.widget->raise(); + that->qt.widget->move(0, 0); + } + that->qt.widget->show(); + } else if (that->qt.widget) { + that->qt.widget->hide(); + } + break; + + case WM_ERASEBKGND: + that->updateMask(); + break; + + case WM_SIZE: + that->resize(QSize(LOWORD(lParam), HIWORD(lParam))); + break; + + case WM_SETFOCUS: + if (that->isInPlaceActive && that->m_spClientSite && !that->inDesignMode && that->canTakeFocus) { + that->DoVerb(OLEIVERB_UIACTIVATE, NULL, that->m_spClientSite, 0, that->m_hWnd, &rcPos); + if (that->isUIActive) { + IOleControlSite *spSite = 0; + that->m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&spSite); + if (spSite) { + spSite->OnFocus(true); + spSite->Release(); + } + QWidget *candidate = that->qt.widget; + while (!(candidate->focusPolicy() & Qt::TabFocus)) { + candidate = candidate->nextInFocusChain(); + if (candidate == that->qt.widget) { + candidate = 0; + break; + } + } + if (candidate) { + candidate->setFocus(); + HackWidget *widget = (HackWidget*)that->qt.widget; + if (::GetKeyState(VK_SHIFT) < 0) + widget->focusNextPrevChild(false); + } + } + } + break; + + case WM_KILLFOCUS: + if (that->isInPlaceActive && that->isUIActive && that->m_spClientSite) { + IOleControlSite *spSite = 0; + that->m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&spSite); + if (spSite) { + if (!::IsChild(that->m_hWnd, ::GetFocus())) + spSite->OnFocus(false); + spSite->Release(); + } + } + break; + + case WM_MOUSEACTIVATE: + that->DoVerb(OLEIVERB_UIACTIVATE, NULL, that->m_spClientSite, 0, that->m_hWnd, &rcPos); + break; + + case WM_INITMENUPOPUP: + if (that->qt.widget) { + that->currentPopup = that->menuMap[(HMENU)wParam]; + if (!that->currentPopup) + break; + const QMetaObject *mo = that->currentPopup->metaObject(); + int index = mo->indexOfSignal("aboutToShow()"); + if (index < 0) + break; + + that->currentPopup->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0); + that->createPopup(that->currentPopup, (HMENU)wParam); + return 0; + } + break; + + case WM_MENUSELECT: + case WM_COMMAND: + if (that->qt.widget) { + QMenuBar *menuBar = that->menuBar; + if (!menuBar) + break; + + QObject *menuObject = 0; + bool menuClosed = false; + + if (uMsg == WM_COMMAND) { + menuObject = that->actionMap.value(wParam); + } else if (!lParam) { + menuClosed = true; + menuObject = that->currentPopup; + } else { + menuObject = that->actionMap.value(LOWORD(wParam)); + } + + if (menuObject) { + const QMetaObject *mo = menuObject->metaObject(); + int index = -1; + + if (uMsg == WM_COMMAND) + index = mo->indexOfSignal("activated()"); + else if (menuClosed) + index = mo->indexOfSignal("aboutToHide()"); + else + index = mo->indexOfSignal("hovered()"); + + if (index < 0) + break; + + menuObject->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0); + if (menuClosed || uMsg == WM_COMMAND) + that->currentPopup = 0; + return 0; + } + } + break; + + default: + break; + } + } + + return ::DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +/*! + Creates the window hosting the QWidget. +*/ +HWND QAxServerBase::create(HWND hWndParent, RECT& rcPos) +{ + Q_ASSERT(isWidget && qt.widget); + + static ATOM atom = 0; + HINSTANCE hInst = (HINSTANCE)qAxInstance; + EnterCriticalSection(&createWindowSection); + QString cn(QLatin1String("QAxControl")); + cn += QString::number((quintptr)ActiveXProc); + if (!atom) { + WNDCLASS wcTemp; + wcTemp.style = CS_DBLCLKS; + wcTemp.cbClsExtra = 0; + wcTemp.cbWndExtra = 0; + wcTemp.hbrBackground = 0; + wcTemp.hCursor = 0; + wcTemp.hIcon = 0; + wcTemp.hInstance = hInst; + wcTemp.lpszClassName = (wchar_t*)cn.utf16(); + wcTemp.lpszMenuName = 0; + wcTemp.lpfnWndProc = ActiveXProc; + + atom = RegisterClass(&wcTemp); + } + LeaveCriticalSection(&createWindowSection); + if (!atom && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + return 0; + + Q_ASSERT(!m_hWnd); + HWND hWnd = ::CreateWindow((wchar_t*)cn.utf16(), 0, + WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + rcPos.left, rcPos.top, rcPos.right - rcPos.left, + rcPos.bottom - rcPos.top, hWndParent, 0, hInst, this); + + Q_ASSERT(m_hWnd == hWnd); + + updateMask(); + EnableWindow(m_hWnd, qt.widget->isEnabled()); + + return hWnd; +} + +/* + Recoursively creates Win32 submenus. +*/ +HMENU QAxServerBase::createPopup(QMenu *popup, HMENU oldMenu) +{ + HMENU popupMenu = oldMenu ? oldMenu : CreatePopupMenu(); + menuMap.insert(popupMenu, popup); + + if (oldMenu) while (GetMenuItemCount(oldMenu)) { + DeleteMenu(oldMenu, 0, MF_BYPOSITION); + } + + const QList<QAction*> actions = popup->actions(); + for (int i = 0; i < actions.count(); ++i) { + QAction *action = actions.at(i); + + uint flags = action->isEnabled() ? MF_ENABLED : MF_GRAYED; + if (action->isSeparator()) + flags |= MF_SEPARATOR; + else if (action->menu()) + flags |= MF_POPUP; + else + flags |= MF_STRING; + if (action->isChecked()) + flags |= MF_CHECKED; + + ushort itemId; + if (flags & MF_POPUP) { + itemId = static_cast<ushort>( + reinterpret_cast<quintptr>(createPopup(action->menu())) + ); + } else { + itemId = static_cast<ushort>(reinterpret_cast<quintptr>(action)); + actionMap.remove(itemId); + actionMap.insert(itemId, action); + } + AppendMenu(popupMenu, flags, itemId, (const wchar_t *)action->text().utf16()); + } + if (oldMenu) + DrawMenuBar(hwndMenuOwner); + return popupMenu; +} + +/*! + Creates a Win32 menubar. +*/ +void QAxServerBase::createMenu(QMenuBar *menuBar) +{ + hmenuShared = ::CreateMenu(); + + int edit = 0; + int object = 0; + int help = 0; + + const QList<QAction*> actions = menuBar->actions(); + for (int i = 0; i < actions.count(); ++i) { + QAction *action = actions.at(i); + + uint flags = action->isEnabled() ? MF_ENABLED : MF_GRAYED; + if (action->isSeparator()) + flags |= MF_SEPARATOR; + else if (action->menu()) + flags |= MF_POPUP; + else + flags |= MF_STRING; + + if (action->text() == QCoreApplication::translate(qt.widget->metaObject()->className(), "&Edit")) + edit++; + else if (action->text() == QCoreApplication::translate(qt.widget->metaObject()->className(), "&Help")) + help++; + else + object++; + + ushort itemId; + if (flags & MF_POPUP) { + itemId = static_cast<ushort>( + reinterpret_cast<quintptr>(createPopup(action->menu())) + ); + } else { + itemId = static_cast<ushort>(reinterpret_cast<quintptr>(action)); + actionMap.insert(itemId, action); + } + AppendMenu(hmenuShared, flags, itemId, (const wchar_t *)action->text().utf16()); + } + + OLEMENUGROUPWIDTHS menuWidths = {0,edit,0,object,0,help}; + HRESULT hres = m_spInPlaceFrame->InsertMenus(hmenuShared, &menuWidths); + if (FAILED(hres)) { + ::DestroyMenu(hmenuShared); + hmenuShared = 0; + return; + } + + m_spInPlaceFrame->GetWindow(&hwndMenuOwner); + + holemenu = OleCreateMenuDescriptor(hmenuShared, &menuWidths); + hres = m_spInPlaceFrame->SetMenu(hmenuShared, holemenu, m_hWnd); + if (FAILED(hres)) { + ::DestroyMenu(hmenuShared); + hmenuShared = 0; + OleDestroyMenuDescriptor(holemenu); + } +} + +/*! + Remove the Win32 menubar. +*/ +void QAxServerBase::removeMenu() +{ + if (hmenuShared) + m_spInPlaceFrame->RemoveMenus(hmenuShared); + holemenu = 0; + m_spInPlaceFrame->SetMenu(0, 0, m_hWnd); + if (hmenuShared) { + DestroyMenu(hmenuShared); + hmenuShared = 0; + menuMap.clear(); + } + hwndMenuOwner = 0; +} + +extern bool ignoreSlots(const char *test); +extern bool ignoreProps(const char *test); + +/*! + Makes sure the type info is loaded +*/ +void QAxServerBase::ensureMetaData() +{ + if (!m_spTypeInfo) { + qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->interfaceID(class_name), &m_spTypeInfo); + m_spTypeInfo->AddRef(); + } +} + +/*! + \internal + Returns true if the property \a index is exposed to COM and should + be saved/loaded. +*/ +bool QAxServerBase::isPropertyExposed(int index) +{ + if (!theObject) + return false; + + bool result = false; + const QMetaObject *mo = theObject->metaObject(); + + int qtProps = 0; + if (theObject->isWidgetType()) + qtProps = QWidget::staticMetaObject.propertyCount(); + QMetaProperty property = mo->property(index); + if (index <= qtProps && ignoreProps(property.name())) + return result; + + BSTR bstrNames = QStringToBSTR(QLatin1String(property.name())); + DISPID dispId; + GetIDsOfNames(IID_NULL, (BSTR*)&bstrNames, 1, LOCALE_USER_DEFAULT, &dispId); + result = dispId != DISPID_UNKNOWN; + SysFreeString(bstrNames); + + return result; +} + + +/*! + \internal + Updates the view, or asks the client site to do so. +*/ +void QAxServerBase::update() +{ + if (isInPlaceActive) { + if (m_hWnd) + ::InvalidateRect(m_hWnd, 0, true); + else if (m_spInPlaceSite) + m_spInPlaceSite->InvalidateRect(NULL, true); + } else if (m_spAdviseSink) { + m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1); + for (int i = 0; i < adviseSinks.count(); ++i) { + adviseSinks.at(i).pAdvSink->OnViewChange(DVASPECT_CONTENT, -1); + } + } +} + +/*! + Resizes the control, faking a QResizeEvent if required +*/ +void QAxServerBase::resize(const QSize &size) +{ + if (!isWidget || !qt.widget || !size.isValid() || size == QSize(0, 0)) + return; + + QSize oldSize = qt.widget->size(); + qt.widget->resize(size); + QSize newSize = qt.widget->size(); + // make sure we get a resize event even if not embedded as a control + if (!m_hWnd && !qt.widget->isVisible() && newSize != oldSize) { + QResizeEvent resizeEvent(newSize, oldSize); +#ifndef QT_DLL // import from static library + extern bool qt_sendSpontaneousEvent(QObject*,QEvent*); +#endif + qt_sendSpontaneousEvent(qt.widget, &resizeEvent); + } + m_currentExtent = qt.widget->size(); +} + +/*! + \internal + + Updates the internal size values. +*/ +void QAxServerBase::updateGeometry() +{ + if (!isWidget || !qt.widget) + return; + + const QSize sizeHint = qt.widget->sizeHint(); + const QSize size = qt.widget->size(); + if (sizeHint.isValid()) { // if provided, adjust to sizeHint + QSize newSize = size; + if (!qt.widget->testAttribute(Qt::WA_Resized)) { + newSize = sizeHint; + } else { // according to sizePolicy rules if already resized + QSizePolicy sizePolicy = qt.widget->sizePolicy(); + if (sizeHint.width() > size.width() && !(sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag)) + newSize.setWidth(sizeHint.width()); + if (sizeHint.width() < size.width() && !(sizePolicy.horizontalPolicy() & QSizePolicy::GrowFlag)) + newSize.setWidth(sizeHint.width()); + if (sizeHint.height() > size.height() && !(sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag)) + newSize.setHeight(sizeHint.height()); + if (sizeHint.height() < size.height() && !(sizePolicy.verticalPolicy() & QSizePolicy::GrowFlag)) + newSize.setHeight(sizeHint.height()); + } + resize(newSize); + + // set an initial size suitable for embedded controls + } else if (!qt.widget->testAttribute(Qt::WA_Resized)) { + resize(QSize(100, 100)); + qt.widget->setAttribute(Qt::WA_Resized, false); + } +} + +/*! + \internal + + Updates the mask of the widget parent. +*/ +void QAxServerBase::updateMask() +{ + if (!isWidget || !qt.widget || qt.widget->mask().isEmpty()) + return; + + QRegion rgn = qt.widget->mask(); + HRGN hrgn = rgn.handle(); + + // Since SetWindowRegion takes ownership + HRGN wr = CreateRectRgn(0,0,0,0); + CombineRgn(wr, hrgn, 0, RGN_COPY); + SetWindowRgn(m_hWnd, wr, true); +} + +static bool checkHRESULT(HRESULT hres) +{ + const char *name = 0; + switch(hres) { + case S_OK: + return true; + case DISP_E_BADPARAMCOUNT: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Bad parameter count", name); +#endif + return false; + case DISP_E_BADVARTYPE: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Bad variant type", name); +#endif + return false; + case DISP_E_EXCEPTION: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Exception thrown by server", name); +#endif + return false; + case DISP_E_MEMBERNOTFOUND: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Member not found", name); +#endif + return false; + case DISP_E_NONAMEDARGS: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: No named arguments", name); +#endif + return false; + case DISP_E_OVERFLOW: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Overflow", name); +#endif + return false; + case DISP_E_PARAMNOTFOUND: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Parameter not found", name); +#endif + return false; + case DISP_E_TYPEMISMATCH: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Type mismatch", name); +#endif + return false; + case DISP_E_UNKNOWNINTERFACE: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Unknown interface", name); +#endif + return false; + case DISP_E_UNKNOWNLCID: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Unknown locale ID", name); +#endif + return false; + case DISP_E_PARAMNOTOPTIONAL: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Non-optional parameter missing", name); +#endif + return false; + default: +#if defined(QT_CHECK_STATE) + qWarning("QAxBase: Error calling IDispatch member %s: Unknown error", name); +#endif + return false; + } +} + +static inline QByteArray paramType(const QByteArray &ptype, bool *out) +{ + *out = ptype.endsWith('&') || ptype.endsWith("**"); + if (*out) { + QByteArray res(ptype); + res.truncate(res.length() - 1); + return res; + } + + return ptype; +} + +/*! + Catches all signals emitted by the Qt widget and fires the respective COM event. + + \a isignal is the Qt Meta Object index of the received signal, and \a _o the + signal parameters. +*/ +int QAxServerBase::qt_metacall(QMetaObject::Call call, int index, void **argv) +{ + Q_ASSERT(call == QMetaObject::InvokeMetaMethod); + + if (index == -1) { + if (sender() && m_spInPlaceFrame) { + if (qobject_cast<QStatusBar*>(sender()) != statusBar) + return true; + + if (statusBar->isHidden()) { + QString message = *(QString*)argv[1]; + m_spInPlaceFrame->SetStatusText(QStringToBSTR(message)); + } + } + return true; + } + + if (freezeEvents || inDesignMode) + return true; + + ensureMetaData(); + + // get the signal information. + const QMetaObject *mo = qt.object->metaObject(); + QMetaMethod signal; + DISPID eventId = index; + int pcount = 0; + QByteArray type; + QList<QByteArray> ptypes; + + switch(index) { + case DISPID_KEYDOWN: + case DISPID_KEYUP: + pcount = 2; + ptypes << "int&" << "int"; + break; + case DISPID_KEYPRESS: + pcount = 1; + ptypes << "int&"; + break; + case DISPID_MOUSEDOWN: + case DISPID_MOUSEMOVE: + case DISPID_MOUSEUP: + pcount = 4; + ptypes << "int" << "int" << "int" << "int"; + break; + case DISPID_CLICK: + pcount = 0; + break; + case DISPID_DBLCLICK: + pcount = 0; + break; + default: + { + signal = mo->method(index); + Q_ASSERT(signal.methodType() == QMetaMethod::Signal); + type = signal.typeName(); + QByteArray signature(signal.signature()); + QByteArray name(signature); + name.truncate(name.indexOf('(')); + + eventId = signalCache.value(index, -1); + if (eventId == -1) { + ITypeInfo *eventInfo = 0; + qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->eventsID(class_name), &eventInfo); + if (eventInfo) { + QString uni_name = QLatin1String(name); + const OLECHAR *olename = reinterpret_cast<const OLECHAR *>(uni_name.utf16()); + eventInfo->GetIDsOfNames((OLECHAR**)&olename, 1, &eventId); + eventInfo->Release(); + } + } + + signature = signature.mid(name.length() + 1); + signature.truncate(signature.length() - 1); + + if (!signature.isEmpty()) + ptypes = signature.split(','); + + pcount = ptypes.count(); + } + break; + } + if (pcount && !argv) { + qWarning("QAxServerBase::qt_metacall: Missing %d arguments", pcount); + return false; + } + if (eventId == -1) + return false; + + // For all connected event sinks... + IConnectionPoint *cpoint = 0; + GUID IID_QAxEvents = qAxFactory()->eventsID(class_name); + FindConnectionPoint(IID_QAxEvents, &cpoint); + if (cpoint) { + IEnumConnections *clist = 0; + cpoint->EnumConnections(&clist); + if (clist) { + clist->Reset(); + ULONG cc = 1; + CONNECTDATA c[1]; + clist->Next(cc, (CONNECTDATA*)&c, &cc); + if (cc) { + // setup parameters + unsigned int argErr = 0; + DISPPARAMS dispParams; + dispParams.cArgs = pcount; + dispParams.cNamedArgs = 0; + dispParams.rgdispidNamedArgs = 0; + dispParams.rgvarg = 0; + + if (pcount) // Use malloc/free for eval package compatibility + dispParams.rgvarg = (VARIANTARG*)malloc(pcount * sizeof(VARIANTARG)); + int p = 0; + for (p = 0; p < pcount; ++p) { + VARIANT *arg = dispParams.rgvarg + (pcount - p - 1); + VariantInit(arg); + + bool out; + QByteArray ptype = paramType(ptypes.at(p), &out); + QVariant variant; + if (mo->indexOfEnumerator(ptype) != -1) { + // convert enum values to int + variant = QVariant(*reinterpret_cast<int *>(argv[p+1])); + } else { + QVariant::Type vt = QVariant::nameToType(ptype); + if (vt == QVariant::UserType) { + if (ptype.endsWith('*')) { + variant = QVariant(QMetaType::type(ptype), (void**)argv[p+1]); + // variant.setValue(*(void**)(argv[p + 1]), ptype); + } else { + variant = QVariant(QMetaType::type(ptype), argv[p+1]); + // variant.setValue(argv[p + 1], ptype); + } + } else { + variant = QVariant(vt, argv[p + 1]); + } + } + + QVariantToVARIANT(variant, *arg, type, out); + } + + VARIANT retval; + VariantInit(&retval); + VARIANT *pretval = 0; + if (!type.isEmpty()) + pretval = &retval; + + // call listeners (through IDispatch) + while (cc) { + if (c->pUnk) { + IDispatch *disp = 0; + c->pUnk->QueryInterface(IID_QAxEvents, (void**)&disp); + if (disp) { + disp->Invoke(eventId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, pretval, 0, &argErr); + + // update out-parameters and return value + if (index > 0) { + for (p = 0; p < pcount; ++p) { + bool out; + QByteArray ptype = paramType(ptypes.at(p), &out); + if (out) + QVariantToVoidStar(VARIANTToQVariant(dispParams.rgvarg[pcount - p - 1], ptype), argv[p+1], ptype); + } + if (pretval) + QVariantToVoidStar(VARIANTToQVariant(retval, type), argv[0], type); + } + disp->Release(); + } + c->pUnk->Release(); // AddRef'ed by clist->Next implementation + } + clist->Next(cc, (CONNECTDATA*)&c, &cc); + } + + // clean up + for (p = 0; p < pcount; ++p) + clearVARIANT(dispParams.rgvarg+p); + free(dispParams.rgvarg); + } + clist->Release(); + } + cpoint->Release(); + } + + return true; +} + +/*! + Call IPropertyNotifySink of connected clients. + \a dispId specifies the ID of the property that changed. +*/ +bool QAxServerBase::emitRequestPropertyChange(const char *property) +{ + long dispId = -1; + + IConnectionPoint *cpoint = 0; + FindConnectionPoint(IID_IPropertyNotifySink, &cpoint); + if (cpoint) { + IEnumConnections *clist = 0; + cpoint->EnumConnections(&clist); + if (clist) { + clist->Reset(); + ULONG cc = 1; + CONNECTDATA c[1]; + clist->Next(cc, (CONNECTDATA*)&c, &cc); + if (cc) { + if (dispId == -1) { + BSTR bstr = QStringToBSTR(QLatin1String(property)); + GetIDsOfNames(IID_NULL, &bstr, 1, LOCALE_USER_DEFAULT, &dispId); + SysFreeString(bstr); + } + if (dispId != -1) while (cc) { + if (c->pUnk) { + IPropertyNotifySink *sink = 0; + c->pUnk->QueryInterface(IID_IPropertyNotifySink, (void**)&sink); + bool disallows = sink && sink->OnRequestEdit(dispId) == S_FALSE; + sink->Release(); + c->pUnk->Release(); + if (disallows) { // a client disallows the property to change + clist->Release(); + cpoint->Release(); + return false; + } + } + clist->Next(cc, (CONNECTDATA*)&c, &cc); + } + } + clist->Release(); + } + cpoint->Release(); + } + dirtyflag = true; + return true; +} + +/*! + Call IPropertyNotifySink of connected clients. + \a dispId specifies the ID of the property that changed. +*/ +void QAxServerBase::emitPropertyChanged(const char *property) +{ + long dispId = -1; + + IConnectionPoint *cpoint = 0; + FindConnectionPoint(IID_IPropertyNotifySink, &cpoint); + if (cpoint) { + IEnumConnections *clist = 0; + cpoint->EnumConnections(&clist); + if (clist) { + clist->Reset(); + ULONG cc = 1; + CONNECTDATA c[1]; + clist->Next(cc, (CONNECTDATA*)&c, &cc); + if (cc) { + if (dispId == -1) { + BSTR bstr = QStringToBSTR(QLatin1String(property)); + GetIDsOfNames(IID_NULL, &bstr, 1, LOCALE_USER_DEFAULT, &dispId); + SysFreeString(bstr); + } + if (dispId != -1) while (cc) { + if (c->pUnk) { + IPropertyNotifySink *sink = 0; + c->pUnk->QueryInterface(IID_IPropertyNotifySink, (void**)&sink); + if (sink) { + sink->OnChanged(dispId); + sink->Release(); + } + c->pUnk->Release(); + } + clist->Next(cc, (CONNECTDATA*)&c, &cc); + } + } + clist->Release(); + } + cpoint->Release(); + } + dirtyflag = true; +} + +//**** IProvideClassInfo +/* + Provide the ITypeInfo implementation for the COM class. +*/ +HRESULT WINAPI QAxServerBase::GetClassInfo(ITypeInfo** pptinfo) +{ + if (!pptinfo) + return E_POINTER; + + *pptinfo = 0; + if (!qAxTypeLibrary) + return DISP_E_BADINDEX; + + return qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->classID(class_name), pptinfo); +} + +//**** IProvideClassInfo2 +/* + Provide the ID of the event interface. +*/ +HRESULT WINAPI QAxServerBase::GetGUID(DWORD dwGuidKind, GUID* pGUID) +{ + if (!pGUID) + return E_POINTER; + + if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID) { + *pGUID = qAxFactory()->eventsID(class_name); + return S_OK; + } + *pGUID = GUID_NULL; + return E_FAIL; +} + +//**** IDispatch +/* + Returns the number of class infos for this IDispatch. +*/ +HRESULT WINAPI QAxServerBase::GetTypeInfoCount(UINT* pctinfo) +{ + if (!pctinfo) + return E_POINTER; + + *pctinfo = qAxTypeLibrary ? 1 : 0; + return S_OK; +} + +/* + Provides the ITypeInfo for this IDispatch implementation. +*/ +HRESULT WINAPI QAxServerBase::GetTypeInfo(UINT itinfo, LCID /*lcid*/, ITypeInfo** pptinfo) +{ + if (!pptinfo) + return E_POINTER; + + if (!qAxTypeLibrary) + return DISP_E_BADINDEX; + + ensureMetaData(); + + *pptinfo = m_spTypeInfo; + (*pptinfo)->AddRef(); + + return S_OK; +} + +/* + Provides the names of the methods implemented in this IDispatch implementation. +*/ +HRESULT WINAPI QAxServerBase::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, + LCID /*lcid*/, DISPID* rgdispid) +{ + if (!rgszNames || !rgdispid) + return E_POINTER; + + if (!qAxTypeLibrary) + return DISP_E_UNKNOWNNAME; + + ensureMetaData(); + if (!m_spTypeInfo) + return DISP_E_UNKNOWNNAME; + + return m_spTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid); +} + +/* + Map the COM call to the Qt slot/property for \a dispidMember. +*/ +HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid, + LCID /*lcid*/, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, + EXCEPINFO* pexcepinfo, UINT* puArgErr) +{ + if (riid != IID_NULL) + return DISP_E_UNKNOWNINTERFACE; + if (!theObject) + return E_UNEXPECTED; + + HRESULT res = DISP_E_MEMBERNOTFOUND; + + bool uniqueIndex = wFlags == DISPATCH_PROPERTYGET || wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_METHOD; + + int index = uniqueIndex ? indexCache.value(dispidMember, -1) : -1; + QByteArray name; + if (index == -1) { + ensureMetaData(); + + // This property or method is invoked when an ActiveX client specifies + // the object name without a property or method. We only support property. + if (dispidMember == DISPID_VALUE && (wFlags == DISPATCH_PROPERTYGET || wFlags == DISPATCH_PROPERTYPUT)) { + const QMetaObject *mo = qt.object->metaObject(); + index = mo->indexOfClassInfo("DefaultProperty"); + if (index != -1) { + name = mo->classInfo(index).value(); + index = mo->indexOfProperty(name); + } + } else { + BSTR bname; + UINT cname = 0; + if (m_spTypeInfo) + m_spTypeInfo->GetNames(dispidMember, &bname, 1, &cname); + if (!cname) + return res; + + name = QString::fromWCharArray(bname).toLatin1(); + SysFreeString(bname); + } + } + + const QMetaObject *mo = qt.object->metaObject(); + QSize oldSizeHint; + if (isWidget) + oldSizeHint = qt.widget->sizeHint(); + + switch (wFlags) { + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + case DISPATCH_PROPERTYGET: + { + if (index == -1) { + index = mo->indexOfProperty(name); + if (index == -1 && wFlags == DISPATCH_PROPERTYGET) + return res; + } + + QMetaProperty property; + if (index < mo->propertyCount()) + property = mo->property(index); + + if (property.isReadable()) { + if (!pvarResult) + return DISP_E_PARAMNOTOPTIONAL; + if (pDispParams->cArgs || + pDispParams->cNamedArgs) + return DISP_E_BADPARAMCOUNT; + + QVariant var = qt.object->property(property.name()); + if (!var.isValid()) + res = DISP_E_MEMBERNOTFOUND; + else if (!QVariantToVARIANT(var, *pvarResult)) + res = DISP_E_TYPEMISMATCH; + else + res = S_OK; + break; + } else if (wFlags == DISPATCH_PROPERTYGET) { + break; + } + } + // FALLTHROUGH if wFlags == DISPATCH_PROPERTYGET|DISPATCH_METHOD AND not a property. + case DISPATCH_METHOD: + { + int nameLength = 0; + if (index == -1) { + nameLength = name.length(); + name += '('; + // no parameter - shortcut + if (!pDispParams->cArgs) + index = mo->indexOfSlot((name + ')')); + // search + if (index == -1) { + for (int i = 0; i < mo->methodCount(); ++i) { + const QMetaMethod slot(mo->method(i)); + if (slot.methodType() == QMetaMethod::Slot && QByteArray(slot.signature()).startsWith(name)) { + index = i; + break; + } + } + // resolve overloads + if (index == -1) { + QRegExp regexp(QLatin1String("_([0-9])\\(")); + if (regexp.lastIndexIn(QString::fromLatin1(name.constData())) != -1) { + name = name.left(name.length() - regexp.cap(0).length()) + '('; + int overload = regexp.cap(1).toInt() + 1; + + for (int s = 0; s < qt.object->metaObject()->methodCount(); ++s) { + QMetaMethod slot = qt.object->metaObject()->method(s); + if (slot.methodType() == QMetaMethod::Slot && QByteArray(slot.signature()).startsWith(name)) { + if (!--overload) { + index = s; + break; + } + } + } + } + } + if (index == -1) + return res; + } + } + + int lookupIndex = index; + + // get slot info + QMetaMethod slot(mo->method(index)); + Q_ASSERT(slot.methodType() == QMetaMethod::Slot); + QByteArray type = slot.typeName(); + name = slot.signature(); + nameLength = name.indexOf('('); + QByteArray prototype = name.mid(nameLength + 1); + prototype.truncate(prototype.length() - 1); + QList<QByteArray> ptypes; + if (!prototype.isEmpty()) + ptypes = prototype.split(','); + int pcount = ptypes.count(); + + // verify parameter count + if (pcount > pDispParams->cArgs) { + // count cloned slots immediately following the real thing + int defArgs = 0; + while (index < mo->methodCount()) { + ++index; + slot = mo->method(index); + if (!(slot.attributes() & QMetaMethod::Cloned)) + break; + --pcount; + // found a matching overload. ptypes still valid + if (pcount <= pDispParams->cArgs) + break; + } + // still wrong :( + if (pcount > pDispParams->cArgs) + return DISP_E_PARAMNOTOPTIONAL; + } else if (pcount < pDispParams->cArgs) { + return DISP_E_BADPARAMCOUNT; + } + + // setup parameters (pcount + return) + bool ok = true; + void *static_argv[QAX_NUM_PARAMS + 1]; + QVariant static_varp[QAX_NUM_PARAMS + 1]; + void *static_argv_pointer[QAX_NUM_PARAMS + 1]; + + int totalParam = pcount; + if (!type.isEmpty()) + ++totalParam; + + void **argv = 0; // the actual array passed into qt_metacall + void **argv_pointer = 0; // in case we need an additional level of indirection + QVariant *varp = 0; // QVariants to hold the temporary Qt data object for us + + if (totalParam) { + if (totalParam <= QAX_NUM_PARAMS) { + argv = static_argv; + argv_pointer = static_argv_pointer; + varp = static_varp; + } else { + argv = new void*[pcount + 1]; + argv_pointer = new void*[pcount + 1]; + varp = new QVariant[pcount + 1]; + } + + argv_pointer[0] = 0; + } + + for (int p = 0; p < pcount; ++p) { + // map the VARIANT to the void* + bool out; + QByteArray ptype = paramType(ptypes.at(p), &out); + varp[p + 1] = VARIANTToQVariant(pDispParams->rgvarg[pcount - p - 1], ptype); + argv_pointer[p + 1] = 0; + if (varp[p + 1].isValid()) { + if (varp[p + 1].type() == QVariant::UserType) { + argv[p + 1] = varp[p + 1].data(); + } else if (ptype == "QVariant") { + argv[p + 1] = varp + p + 1; + } else { + argv[p + 1] = const_cast<void*>(varp[p + 1].constData()); + if (ptype.endsWith('*')) { + argv_pointer[p + 1] = argv[p + 1]; + argv[p + 1] = argv_pointer + p + 1; + } + } + } else if (ptype == "QVariant") { + argv[p + 1] = varp + p + 1; + } else { + if (puArgErr) + *puArgErr = pcount-p-1; + ok = false; + } + } + + // return value + if (!type.isEmpty()) { + QVariant::Type vt = QVariant::nameToType(type); + if (vt == QVariant::UserType) + vt = QVariant::Invalid; + varp[0] = QVariant(vt); + if (varp[0].type() == QVariant::Invalid && mo->indexOfEnumerator(slot.typeName()) != -1) + varp[0] = QVariant(QVariant::Int); + + if (varp[0].type() == QVariant::Invalid) { + if (type == "QVariant") + argv[0] = varp; + else + argv[0] = 0; + } else { + argv[0] = const_cast<void*>(varp[0].constData()); + } + if (type.endsWith('*')) { + argv_pointer[0] = argv[0]; + argv[0] = argv_pointer; + } + } + + // call the slot if everthing went fine. + if (ok) { + ++invokeCount; + qt.object->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv); + if (--invokeCount < 0) + invokeCount = 0; + + // update reference parameters and return value + for (int p = 0; p < pcount; ++p) { + bool out; + QByteArray ptype = paramType(ptypes.at(p), &out); + if (out) { + if (!QVariantToVARIANT(varp[p + 1], pDispParams->rgvarg[pcount - p - 1], ptype, out)) + ok = false; + } + } + if (!type.isEmpty() && pvarResult) { + if (!varp[0].isValid() && type != "QVariant") + varp[0] = QVariant(QMetaType::type(type), argv_pointer); +// varp[0].setValue(argv_pointer[0], type); + ok = QVariantToVARIANT(varp[0], *pvarResult, type); + } + } + if (argv && argv != static_argv) { + delete []argv; + delete []argv_pointer; + delete []varp; + } + + res = ok ? S_OK : DISP_E_TYPEMISMATCH; + + // reset in case index changed for default-arg handling + index = lookupIndex; + } + break; + case DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF: + { + if (index == -1) { + index = mo->indexOfProperty(name); + if (index == -1) + return res; + } + + QMetaProperty property; + if (index < mo->propertyCount()) + property = mo->property(index); + if (!property.isWritable()) + return DISP_E_MEMBERNOTFOUND; + if (!pDispParams->cArgs) + return DISP_E_PARAMNOTOPTIONAL; + if (pDispParams->cArgs != 1 || + pDispParams->cNamedArgs != 1 || + *pDispParams->rgdispidNamedArgs != DISPID_PROPERTYPUT) + return DISP_E_BADPARAMCOUNT; + + QVariant var = VARIANTToQVariant(*pDispParams->rgvarg, property.typeName(), property.type()); + if (!var.isValid()) { + if (puArgErr) + *puArgErr = 0; + return DISP_E_BADVARTYPE; + } + if (!qt.object->setProperty(property.name(), var)) { + if (puArgErr) + *puArgErr = 0; + return DISP_E_TYPEMISMATCH; + } + + res = S_OK; + } + break; + + default: + break; + } + + // maybe calling a setter? Notify client about changes + switch(wFlags) { + case DISPATCH_METHOD: + case DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF: + if (m_spAdviseSink || adviseSinks.count()) { + FORMATETC fmt; + fmt.cfFormat = 0; + fmt.ptd = 0; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.tymed = TYMED_NULL; + + STGMEDIUM stg; + stg.tymed = TYMED_NULL; + stg.pUnkForRelease = 0; + stg.hBitmap = 0; // initializes the whole union + + if (m_spAdviseSink) { + m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1); + m_spAdviseSink->OnDataChange(&fmt, &stg); + } + for (int i = 0; i < adviseSinks.count(); ++i) { + adviseSinks.at(i).pAdvSink->OnDataChange(&fmt, &stg); + } + } + + dirtyflag = true; + break; + default: + break; + } + + if (index != -1 && uniqueIndex) + indexCache.insert(dispidMember, index); + + if (exception) { + if (pexcepinfo) { + memset(pexcepinfo, 0, sizeof(EXCEPINFO)); + + pexcepinfo->wCode = exception->code; + if (!exception->src.isNull()) + pexcepinfo->bstrSource = QStringToBSTR(exception->src); + if (!exception->desc.isNull()) + pexcepinfo->bstrDescription = QStringToBSTR(exception->desc); + if (!exception->context.isNull()) { + QString context = exception->context; + int contextID = 0; + int br = context.indexOf(QLatin1Char('[')); + if (br != -1) { + context = context.mid(br+1); + context = context.left(context.length() - 1); + contextID = context.toInt(); + + context = exception->context; + context = context.left(br-1); + } + pexcepinfo->bstrHelpFile = QStringToBSTR(context); + pexcepinfo->dwHelpContext = contextID; + } + } + delete exception; + exception = 0; + return DISP_E_EXCEPTION; + } else if (isWidget) { + QSize sizeHint = qt.widget->sizeHint(); + if (oldSizeHint != sizeHint) { + updateGeometry(); + if (m_spInPlaceSite) { + RECT rect = {0, 0, sizeHint.width(), sizeHint.height()}; + m_spInPlaceSite->OnPosRectChange(&rect); + } + } + updateMask(); + } + + return res; +} + +//**** IConnectionPointContainer +/* + Provide the IEnumConnectionPoints implemented in the QAxSignalVec class. +*/ +HRESULT WINAPI QAxServerBase::EnumConnectionPoints(IEnumConnectionPoints **epoints) +{ + if (!epoints) + return E_POINTER; + *epoints = new QAxSignalVec(points); + (*epoints)->AddRef(); + return S_OK; +} + +/* + Provide the IConnectionPoint implemented in the QAxConnection for \a iid. +*/ +HRESULT WINAPI QAxServerBase::FindConnectionPoint(REFIID iid, IConnectionPoint **cpoint) +{ + if (!cpoint) + return E_POINTER; + + IConnectionPoint *cp = points[iid]; + *cpoint = cp; + if (cp) { + cp->AddRef(); + return S_OK; + } + return CONNECT_E_NOCONNECTION; +} + +//**** IPersistStream +/* + \reimp + + See documentation of IPersistStorage::IsDirty. +*/ +HRESULT WINAPI QAxServerBase::IsDirty() +{ + return dirtyflag ? S_OK : S_FALSE; +} + +HRESULT WINAPI QAxServerBase::Load(IStream *pStm) +{ + STATSTG stat; + HRESULT hres = pStm->Stat(&stat, STATFLAG_DEFAULT); + bool openAsText = false; + QByteArray qtarray; + if (hres == S_OK) { + QString streamName = QString::fromWCharArray(stat.pwcsName); + CoTaskMemFree(stat.pwcsName); + openAsText = streamName == QLatin1String("SomeStreamName"); + if (stat.cbSize.HighPart) // more than 4GB - too large! + return S_FALSE; + + qtarray.resize(stat.cbSize.LowPart); + ULONG read; + pStm->Read(qtarray.data(), stat.cbSize.LowPart, &read); + } else if (hres == E_NOTIMPL) { + ULONG read = 0; + while (hres != S_FALSE) { + QByteArray arrayRead; + arrayRead.resize(4098); + hres = pStm->Read(arrayRead.data(), arrayRead.size(), &read); + if (hres != S_OK && hres != S_FALSE) { + qtarray.resize(0); + break; + } else if (read == 0) + break; + qtarray.append(arrayRead); + } + } + const QMetaObject *mo = qt.object->metaObject(); + + QBuffer qtbuffer(&qtarray); + QByteArray mimeType = mo->classInfo(mo->indexOfClassInfo("MIME")).value(); + if (!mimeType.isEmpty()) { + mimeType = mimeType.left(mimeType.indexOf(':')); // first type + QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable"); + if (axb && axb->readData(&qtbuffer, QString::fromLatin1(mimeType))) + return S_OK; + } + + qtbuffer.close(); // resets + qtbuffer.open(openAsText ? (QIODevice::ReadOnly | QIODevice::Text) : QIODevice::ReadOnly); + + QDataStream qtstream(&qtbuffer); + int version; + qtstream >> version; + qtstream.setVersion(version); + int more = 0; + qtstream >> more; + + while (!qtbuffer.atEnd() && more) { + QString propname; + QVariant value; + qtstream >> propname; + if (propname.isEmpty()) + break; + qtstream >> value; + qtstream >> more; + + int idx = mo->indexOfProperty(propname.toLatin1()); + QMetaProperty property = mo->property(idx); + if (property.isWritable()) + qt.object->setProperty(propname.toLatin1(), value); + } + return S_OK; +} + +HRESULT WINAPI QAxServerBase::Save(IStream *pStm, BOOL clearDirty) +{ + const QMetaObject *mo = qt.object->metaObject(); + + QBuffer qtbuffer; + bool saved = false; + QByteArray mimeType = mo->classInfo(mo->indexOfClassInfo("MIME")).value(); + if (!mimeType.isEmpty()) { + QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable"); + saved = axb && axb->writeData(&qtbuffer); + qtbuffer.close(); + } + + if (!saved) { + qtbuffer.open(QIODevice::WriteOnly); + QDataStream qtstream(&qtbuffer); + qtstream << qtstream.version(); + + for (int prop = 0; prop < mo->propertyCount(); ++prop) { + if (!isPropertyExposed(prop)) + continue; + QMetaProperty metaprop = mo->property(prop); + if (QByteArray(metaprop.typeName()).endsWith('*')) + continue; + QString property = QLatin1String(metaprop.name()); + QVariant qvar = qt.object->property(metaprop.name()); + if (qvar.isValid()) { + qtstream << int(1); + qtstream << property; + qtstream << qvar; + } + } + + qtstream << int(0); + qtbuffer.close(); + } + + QByteArray qtarray = qtbuffer.buffer(); + ULONG written = 0; + const char *data = qtarray.constData(); + ULARGE_INTEGER newsize; + newsize.HighPart = 0; + newsize.LowPart = qtarray.size(); + pStm->SetSize(newsize); + pStm->Write(data, qtarray.size(), &written); + pStm->Commit(STGC_ONLYIFCURRENT); + + if (clearDirty) + dirtyflag = false; + return S_OK; +} + +HRESULT WINAPI QAxServerBase::GetSizeMax(ULARGE_INTEGER *pcbSize) +{ + const QMetaObject *mo = qt.object->metaObject(); + + int np = mo->propertyCount(); + pcbSize->HighPart = 0; + pcbSize->LowPart = np * 50; + + return S_OK; +} + +//**** IPersistStorage + +HRESULT WINAPI QAxServerBase::InitNew(IStorage *pStg) +{ + if (initNewCalled) + return CO_E_ALREADYINITIALIZED; + + dirtyflag = false; + initNewCalled = true; + + m_spStorage = pStg; + if (m_spStorage) + m_spStorage->AddRef(); + return S_OK; +} + +HRESULT WINAPI QAxServerBase::Load(IStorage *pStg) +{ + if (InitNew(pStg) != S_OK) + return CO_E_ALREADYINITIALIZED; + + IStream *spStream = 0; + QString streamName = QLatin1String(qt.object->metaObject()->className()); + streamName.replace(QLatin1Char(':'), QLatin1Char('.')); + /* Also invalid, but not relevant + streamName.replace(QLatin1Char('/'), QLatin1Char('_')); + streamName.replace(QLatin1Char('\\'), QLatin1Char('_')); + */ + streamName += QLatin1String("_Stream4.2"); + + pStg->OpenStream((const wchar_t *)streamName.utf16(), 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &spStream); + if (!spStream) // support for streams saved with 4.1 and earlier + pStg->OpenStream(L"SomeStreamName", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &spStream); + if (!spStream) + return E_FAIL; + + Load(spStream); + spStream->Release(); + + return S_OK; +} + +HRESULT WINAPI QAxServerBase::Save(IStorage *pStg, BOOL fSameAsLoad) +{ + IStream *spStream = 0; + QString streamName = QLatin1String(qt.object->metaObject()->className()); + streamName.replace(QLatin1Char(':'), QLatin1Char('.')); + /* Also invalid, but not relevant + streamName.replace(QLatin1Char('/'), QLatin1Char('_')); + streamName.replace(QLatin1Char('\\'), QLatin1Char('_')); + */ + streamName += QLatin1String("_Stream4.2"); + + pStg->CreateStream((const wchar_t *)streamName.utf16(), STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &spStream); + if (!spStream) + return E_FAIL; + + Save(spStream, true); + + spStream->Release(); + return S_OK; +} + +HRESULT WINAPI QAxServerBase::SaveCompleted(IStorage *pStgNew) +{ + if (pStgNew) { + if (m_spStorage) + m_spStorage->Release(); + m_spStorage = pStgNew; + m_spStorage->AddRef(); + } + return S_OK; +} + +HRESULT WINAPI QAxServerBase::HandsOffStorage() +{ + if (m_spStorage) m_spStorage->Release(); + m_spStorage = 0; + + return S_OK; +} + +//**** IPersistPropertyBag +/* + Initialize the properties of the Qt widget. +*/ +HRESULT WINAPI QAxServerBase::InitNew() +{ + if (initNewCalled) + return CO_E_ALREADYINITIALIZED; + + dirtyflag = false; + initNewCalled = true; + return S_OK; +} + +/* + Set the properties of the Qt widget to the values provided in the \a bag. +*/ +HRESULT WINAPI QAxServerBase::Load(IPropertyBag *bag, IErrorLog * /*log*/) +{ + if (!bag) + return E_POINTER; + + if (InitNew() != S_OK) + return E_UNEXPECTED; + + bool error = false; + const QMetaObject *mo = qt.object->metaObject(); + for (int prop = 0; prop < mo->propertyCount(); ++prop) { + if (!isPropertyExposed(prop)) + continue; + QMetaProperty property = mo->property(prop); + const char* pname = property.name(); + BSTR bstr = QStringToBSTR(QLatin1String(pname)); + VARIANT var; + var.vt = VT_EMPTY; + HRESULT res = bag->Read(bstr, &var, 0); + if (property.isWritable() && var.vt != VT_EMPTY) { + if (res != S_OK || !qt.object->setProperty(pname, VARIANTToQVariant(var, property.typeName(), property.type()))) + error = true; + } + SysFreeString(bstr); + } + + updateGeometry(); + + return /*error ? E_FAIL :*/ S_OK; +} + +/* + Save the properties of the Qt widget into the \a bag. +*/ +HRESULT WINAPI QAxServerBase::Save(IPropertyBag *bag, BOOL clearDirty, BOOL /*saveAll*/) +{ + if (!bag) + return E_POINTER; + + if (clearDirty) + dirtyflag = false; + bool error = false; + const QMetaObject *mo = qt.object->metaObject(); + for (int prop = 0; prop < mo->propertyCount(); ++prop) { + if (!isPropertyExposed(prop)) + continue; + QMetaProperty property = mo->property(prop); + if (QByteArray(property.typeName()).endsWith('*')) + continue; + + BSTR bstr = QStringToBSTR(QLatin1String(property.name())); + QVariant qvar = qt.object->property(property.name()); + if (!qvar.isValid()) + error = true; + VARIANT var; + QVariantToVARIANT(qvar, var); + bag->Write(bstr, &var); + SysFreeString(bstr); + } + return /*error ? E_FAIL :*/ S_OK; +} + +//**** IPersistFile +/* +*/ +HRESULT WINAPI QAxServerBase::SaveCompleted(LPCOLESTR fileName) +{ + if (qt.object->metaObject()->indexOfClassInfo("MIME") == -1) + return E_NOTIMPL; + + currentFileName = QString::fromWCharArray(fileName); + return S_OK; +} + +HRESULT WINAPI QAxServerBase::GetCurFile(LPOLESTR *currentFile) +{ + if (qt.object->metaObject()->indexOfClassInfo("MIME") == -1) + return E_NOTIMPL; + + if (currentFileName.isEmpty()) { + *currentFile = 0; + return S_FALSE; + } + IMalloc *malloc = 0; + CoGetMalloc(1, &malloc); + if (!malloc) + return E_OUTOFMEMORY; + + *currentFile = static_cast<wchar_t *>(malloc->Alloc(currentFileName.length() * 2)); + malloc->Release(); + memcpy(*currentFile, currentFileName.unicode(), currentFileName.length() * 2); + + return S_OK; +} + +HRESULT WINAPI QAxServerBase::Load(LPCOLESTR fileName, DWORD mode) +{ + const QMetaObject *mo = qt.object->metaObject(); + int mimeIndex = mo->indexOfClassInfo("MIME"); + if (mimeIndex == -1) + return E_NOTIMPL; + + QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable"); + if (!axb) { + qWarning() << class_name << ": No QAxBindable implementation for mime-type handling"; + return E_NOTIMPL; + } + + QString loadFileName = QString::fromWCharArray(fileName); + QString fileExtension = loadFileName.mid(loadFileName.lastIndexOf(QLatin1Char('.')) + 1); + QFile file(loadFileName); + + QString mimeType = QLatin1String(mo->classInfo(mimeIndex).value()); + QStringList mimeTypes = mimeType.split(QLatin1Char(';')); + for (int m = 0; m < mimeTypes.count(); ++m) { + QString mime = mimeTypes.at(m); + if (mime.count(QLatin1Char(':')) != 2) { + qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME"; + continue; + } + + mimeType = mime.left(mimeType.indexOf(QLatin1Char(':'))); // first type + if (mimeType.isEmpty()) { + qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME"; + continue; + } + QString mimeExtension = mime.mid(mimeType.length() + 1); + mimeExtension = mimeExtension.left(mimeExtension.indexOf(QLatin1Char(':'))); + if (mimeExtension != fileExtension) + continue; + + if (axb->readData(&file, mimeType)) { + currentFileName = loadFileName; + return S_OK; + } + } + + return E_FAIL; +} + +HRESULT WINAPI QAxServerBase::Save(LPCOLESTR fileName, BOOL fRemember) +{ + const QMetaObject *mo = qt.object->metaObject(); + int mimeIndex = mo->indexOfClassInfo("MIME"); + if (mimeIndex == -1) + return E_NOTIMPL; + + QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable"); + if (!axb) { + qWarning() << class_name << ": No QAxBindable implementation for mime-type handling"; + return E_NOTIMPL; + } + + QString saveFileName = QString::fromWCharArray(fileName); + QString fileExtension = saveFileName.mid(saveFileName.lastIndexOf(QLatin1Char('.')) + 1); + QFile file(saveFileName); + + QString mimeType = QLatin1String(mo->classInfo(mimeIndex).value()); + QStringList mimeTypes = mimeType.split(QLatin1Char(';')); + for (int m = 0; m < mimeTypes.count(); ++m) { + QString mime = mimeTypes.at(m); + if (mime.count(QLatin1Char(':')) != 2) { + qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME"; + continue; + } + mimeType = mime.left(mimeType.indexOf(QLatin1Char(':'))); // first type + if (mimeType.isEmpty()) { + qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME"; + continue; + } + QString mimeExtension = mime.mid(mimeType.length() + 1); + mimeExtension = mimeExtension.left(mimeExtension.indexOf(QLatin1Char(':'))); + if (mimeExtension != fileExtension) + continue; + if (axb->writeData(&file)) { + if (fRemember) + currentFileName = saveFileName; + return S_OK; + } + } + return E_FAIL; +} + +//**** IViewObject +/* + Draws the widget into the provided device context. +*/ +HRESULT WINAPI QAxServerBase::Draw(DWORD dwAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, + HDC hicTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL /*lprcWBounds*/, + BOOL(__stdcall* /*pfnContinue*/)(ULONG_PTR), ULONG_PTR /*dwContinue*/) +{ + if (!lprcBounds) + return E_INVALIDARG; + + internalCreate(); + if (!isWidget || !qt.widget) + return OLE_E_BLANK; + + switch (dwAspect) { + case DVASPECT_CONTENT: + case DVASPECT_OPAQUE: + case DVASPECT_TRANSPARENT: + break; + default: + return DV_E_DVASPECT; + } + if (!ptd) + hicTargetDev = 0; + + bool bDeleteDC = false; + if (!hicTargetDev) { + hicTargetDev = ::CreateDC(L"DISPLAY", NULL, NULL, NULL); + bDeleteDC = (hicTargetDev != hdcDraw); + } + + RECTL rc = *lprcBounds; + bool bMetaFile = GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE; + if (!bMetaFile) + ::LPtoDP(hicTargetDev, (LPPOINT)&rc, 2); + + QPixmap pm = QPixmap::grabWidget(qt.widget); + HBITMAP hbm = pm.toWinHBITMAP(); + HDC hdc = CreateCompatibleDC(0); + SelectObject(hdc, hbm); + ::StretchBlt(hdcDraw, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0,pm.width(), pm.height(), SRCCOPY); + DeleteDC(hdc); + DeleteObject(hbm); + + if (bDeleteDC) + DeleteDC(hicTargetDev); + + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, + HDC hicTargetDev, LOGPALETTE **ppColorSet) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::Freeze(DWORD dwAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::Unfreeze(DWORD dwFreeze) +{ + return E_NOTIMPL; +} + +/* + Stores the provided advise sink. +*/ +HRESULT WINAPI QAxServerBase::SetAdvise(DWORD /*aspects*/, DWORD /*advf*/, IAdviseSink *pAdvSink) +{ + if (m_spAdviseSink) m_spAdviseSink->Release(); + + m_spAdviseSink = pAdvSink; + if (m_spAdviseSink) m_spAdviseSink->AddRef(); + return S_OK; +} + +/* + Returns the advise sink. +*/ +HRESULT WINAPI QAxServerBase::GetAdvise(DWORD* /*aspects*/, DWORD* /*advf*/, IAdviseSink **ppAdvSink) +{ + if (!ppAdvSink) + return E_POINTER; + + *ppAdvSink = m_spAdviseSink; + if (*ppAdvSink) + (*ppAdvSink)->AddRef(); + return S_OK; +} + +//**** IViewObject2 +/* + Returns the current size ONLY if the widget has already been sized. +*/ +HRESULT WINAPI QAxServerBase::GetExtent(DWORD dwAspect, LONG /*lindex*/, DVTARGETDEVICE* /*ptd*/, LPSIZEL lpsizel) +{ + if (!isWidget || !qt.widget || !qt.widget->testAttribute(Qt::WA_Resized)) + return OLE_E_BLANK; + + return GetExtent(dwAspect, lpsizel); +} + +//**** IOleControl +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::GetControlInfo(LPCONTROLINFO) +{ + return E_NOTIMPL; +} + +/* + Turns event firing on and off. +*/ +HRESULT WINAPI QAxServerBase::FreezeEvents(BOOL bFreeze) +{ + // member of CComControl + if (bFreeze) + freezeEvents++; + else + freezeEvents--; + + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::OnMnemonic(LPMSG) +{ + return E_NOTIMPL; +} + +/* + Update the ambient properties of the Qt widget. +*/ +HRESULT WINAPI QAxServerBase::OnAmbientPropertyChange(DISPID dispID) +{ + if (!m_spClientSite || !theObject) + return S_OK; + + IDispatch *disp = 0; + m_spClientSite->QueryInterface(IID_IDispatch, (void**)&disp); + if (!disp) + return S_OK; + + VARIANT var; + VariantInit(&var); + DISPPARAMS params = { 0, 0, 0, 0 }; + disp->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &var, 0, 0); + disp->Release(); + disp = 0; + + switch(dispID) { + case DISPID_AMBIENT_APPEARANCE: + break; + case DISPID_AMBIENT_AUTOCLIP: + break; + case DISPID_AMBIENT_BACKCOLOR: + case DISPID_AMBIENT_FORECOLOR: + if (isWidget) { + long rgb; + if (var.vt == VT_UI4) + rgb = var.ulVal; + else if (var.vt == VT_I4) + rgb = var.lVal; + else + break; + QPalette pal = qt.widget->palette(); + pal.setColor(dispID == DISPID_AMBIENT_BACKCOLOR ? QPalette::Window : QPalette::WindowText, + OLEColorToQColor(rgb)); + qt.widget->setPalette(pal); + } + break; + case DISPID_AMBIENT_DISPLAYASDEFAULT: + break; + case DISPID_AMBIENT_DISPLAYNAME: + if (var.vt != VT_BSTR || !isWidget) + break; + qt.widget->setWindowTitle(QString::fromWCharArray(var.bstrVal)); + break; + case DISPID_AMBIENT_FONT: + if (var.vt != VT_DISPATCH || !isWidget) + break; + { + QVariant qvar = VARIANTToQVariant(var, "QFont", QVariant::Font); + QFont qfont = qvariant_cast<QFont>(qvar); + qt.widget->setFont(qfont); + } + break; + case DISPID_AMBIENT_LOCALEID: + break; + case DISPID_AMBIENT_MESSAGEREFLECT: + if (var.vt != VT_BOOL) + break; + if (var.boolVal) + qt.widget->installEventFilter(this); + else + qt.widget->removeEventFilter(this); + break; + case DISPID_AMBIENT_PALETTE: + break; + case DISPID_AMBIENT_SCALEUNITS: + break; + case DISPID_AMBIENT_SHOWGRABHANDLES: + break; + case DISPID_AMBIENT_SHOWHATCHING: + break; + case DISPID_AMBIENT_SUPPORTSMNEMONICS: + break; + case DISPID_AMBIENT_TEXTALIGN: + break; + case DISPID_AMBIENT_UIDEAD: + if (var.vt != VT_BOOL || !isWidget) + break; + qt.widget->setEnabled(!var.boolVal); + break; + case DISPID_AMBIENT_USERMODE: + if (var.vt != VT_BOOL) + break; + inDesignMode = !var.boolVal; + break; + case DISPID_AMBIENT_RIGHTTOLEFT: + if (var.vt != VT_BOOL) + break; + qApp->setLayoutDirection(var.boolVal?Qt::RightToLeft:Qt::LeftToRight); + break; + } + + return S_OK; +} + +//**** IOleWindow +/* + Returns the HWND of the control. +*/ +HRESULT WINAPI QAxServerBase::GetWindow(HWND *pHwnd) +{ + if (!pHwnd) + return E_POINTER; + *pHwnd = m_hWnd; + return S_OK; +} + +/* + Enters What's This mode. +*/ +HRESULT WINAPI QAxServerBase::ContextSensitiveHelp(BOOL fEnterMode) +{ + if (fEnterMode) + QWhatsThis::enterWhatsThisMode(); + else + QWhatsThis::leaveWhatsThisMode(); + return S_OK; +} + +//**** IOleInPlaceObject +/* + Deactivates the control in place. +*/ +HRESULT WINAPI QAxServerBase::InPlaceDeactivate() +{ + if (!isInPlaceActive) + return S_OK; + UIDeactivate(); + + isInPlaceActive = false; + + // if we have a window, tell it to go away. + if (m_hWnd) { + if (::IsWindow(m_hWnd)) + ::DestroyWindow(m_hWnd); + m_hWnd = 0; + } + + if (m_spInPlaceSite) + m_spInPlaceSite->OnInPlaceDeactivate(); + + return S_OK; +} + +/* + Deactivates the control's user interface. +*/ +HRESULT WINAPI QAxServerBase::UIDeactivate() +{ + // if we're not UIActive, not much to do. + if (!isUIActive || !m_spInPlaceSite) + return S_OK; + + isUIActive = false; + + // notify frame windows, if appropriate, that we're no longer ui-active. + HWND hwndParent; + if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) { + if (m_spInPlaceFrame) m_spInPlaceFrame->Release(); + m_spInPlaceFrame = 0; + IOleInPlaceUIWindow *spInPlaceUIWindow = 0; + RECT rcPos, rcClip; + OLEINPLACEFRAMEINFO frameInfo; + frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); + + m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo); + if (spInPlaceUIWindow) { + spInPlaceUIWindow->SetActiveObject(0, 0); + spInPlaceUIWindow->Release(); + } + if (m_spInPlaceFrame) { + removeMenu(); + if (menuBar) { + menuBar->removeEventFilter(this); + menuBar = 0; + } + if (statusBar) { + statusBar->removeEventFilter(this); + const int index = statusBar->metaObject()->indexOfSignal("messageChanged(QString)"); + QMetaObject::disconnect(statusBar, index, this, -1); + statusBar = 0; + } + m_spInPlaceFrame->SetActiveObject(0, 0); + m_spInPlaceFrame->Release(); + m_spInPlaceFrame = 0; + } + } + // we don't need to explicitly release the focus here since somebody + // else grabbing the focus is usually why we are getting called at all + m_spInPlaceSite->OnUIDeactivate(false); + + return S_OK; +} + +/* + Positions the control, and applies requested clipping. +*/ +HRESULT WINAPI QAxServerBase::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip) +{ + if (prcPos == 0 || prcClip == 0) + return E_POINTER; + + if (m_hWnd) { + // the container wants us to clip, so figure out if we really need to + RECT rcIXect; + BOOL b = IntersectRect(&rcIXect, prcPos, prcClip); + HRGN tempRgn = 0; + if (b && !EqualRect(&rcIXect, prcPos)) { + OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top)); + tempRgn = CreateRectRgnIndirect(&rcIXect); + } + + ::SetWindowRgn(m_hWnd, tempRgn, true); + ::SetWindowPos(m_hWnd, 0, prcPos->left, prcPos->top, + prcPos->right - prcPos->left, prcPos->bottom - prcPos->top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + + //Save the new extent. + m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), int(prcPos->right - prcPos->left), qt.widget->maximumWidth()); + m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), int(prcPos->bottom - prcPos->top), qt.widget->maximumHeight()); + + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::ReactivateAndUndo() +{ + return E_NOTIMPL; +} + +//**** IOleInPlaceActiveObject + +Q_GUI_EXPORT int qt_translateKeyCode(int); + +HRESULT WINAPI QAxServerBase::TranslateAcceleratorW(MSG *pMsg) +{ + if (pMsg->message != WM_KEYDOWN || !isWidget) + return S_FALSE; + + DWORD dwKeyMod = 0; + if (::GetKeyState(VK_SHIFT) < 0) + dwKeyMod |= 1; // KEYMOD_SHIFT + if (::GetKeyState(VK_CONTROL) < 0) + dwKeyMod |= 2; // KEYMOD_CONTROL + if (::GetKeyState(VK_MENU) < 0) + dwKeyMod |= 4; // KEYMOD_ALT + + switch (LOWORD(pMsg->wParam)) { + case VK_TAB: + if (isUIActive) { + bool shift = ::GetKeyState(VK_SHIFT) < 0; + bool giveUp = true; + QWidget *curFocus = qt.widget->focusWidget(); + if (curFocus) { + if (shift) { + if (!curFocus->isWindow()) { + QWidget *nextFocus = curFocus->nextInFocusChain(); + QWidget *prevFocus = 0; + QWidget *topLevel = 0; + while (nextFocus != curFocus) { + if (nextFocus->focusPolicy() & Qt::TabFocus) { + prevFocus = nextFocus; + topLevel = 0; + } else if (nextFocus->isWindow()) { + topLevel = nextFocus; + } + nextFocus = nextFocus->nextInFocusChain(); + } + + if (!topLevel) { + giveUp = false; + ((HackWidget*)curFocus)->focusNextPrevChild(false); + curFocus->window()->setAttribute(Qt::WA_KeyboardFocusChange); + } + } + } else { + QWidget *nextFocus = curFocus; + while (1) { + nextFocus = nextFocus->nextInFocusChain(); + if (nextFocus->isWindow()) + break; + if (nextFocus->focusPolicy() & Qt::TabFocus) { + giveUp = false; + ((HackWidget*)curFocus)->focusNextPrevChild(true); + curFocus->window()->setAttribute(Qt::WA_KeyboardFocusChange); + break; + } + } + } + } + if (giveUp) { + HWND hwnd = ::GetParent(m_hWnd); + ::SetFocus(hwnd); + } else { + return S_OK; + } + + } + break; + + case VK_LEFT: + case VK_RIGHT: + case VK_UP: + case VK_DOWN: + if (isUIActive) + return S_FALSE; + break; + + default: + if (isUIActive && qt.widget->focusWidget()) { + int state = Qt::NoButton; + if (dwKeyMod & 1) + state |= Qt::ShiftModifier; + if (dwKeyMod & 2) + state |= Qt::ControlModifier; + if (dwKeyMod & 4) + state |= Qt::AltModifier; + + int key = pMsg->wParam; + if (!(key >= 'A' && key <= 'Z') && !(key >= '0' && key <= '9')) + key = qt_translateKeyCode(pMsg->wParam); + + QKeyEvent override(QEvent::ShortcutOverride, key, (Qt::KeyboardModifiers)state); + override.ignore(); + QApplication::sendEvent(qt.widget->focusWidget(), &override); + if (override.isAccepted()) + return S_FALSE; + } + break; + } + + if (!m_spClientSite) + return S_FALSE; + + IOleControlSite *controlSite = 0; + m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&controlSite); + if (!controlSite) + return S_FALSE; + bool resetUserData = false; + // set server type in the user-data of the window. +#ifdef GWLP_USERDATA + LONG_PTR serverType = QAX_INPROC_SERVER; +#else + LONG serverType = QAX_INPROC_SERVER; +#endif + if (qAxOutProcServer) + serverType = QAX_OUTPROC_SERVER; +#ifdef GWLP_USERDATA + LONG_PTR oldData = SetWindowLongPtr(pMsg->hwnd, GWLP_USERDATA, serverType); +#else + LONG oldData = SetWindowLong(pMsg->hwnd, GWL_USERDATA, serverType); +#endif + HRESULT hres = controlSite->TranslateAcceleratorW(pMsg, dwKeyMod); + controlSite->Release(); + // reset the user-data for the window. +#ifdef GWLP_USERDATA + SetWindowLongPtr(pMsg->hwnd, GWLP_USERDATA, oldData); +#else + SetWindowLong(pMsg->hwnd, GWL_USERDATA, oldData); +#endif + return hres; +} + +HRESULT WINAPI QAxServerBase::TranslateAcceleratorA(MSG *pMsg) +{ + return TranslateAcceleratorW(pMsg); +} + +HRESULT WINAPI QAxServerBase::OnFrameWindowActivate(BOOL fActivate) +{ + if (fActivate) { + if (wasUIActive) + ::SetFocus(m_hWnd); + } else { + wasUIActive = isUIActive; + } + return S_OK; +} + +HRESULT WINAPI QAxServerBase::OnDocWindowActivate(BOOL fActivate) +{ + return S_OK; +} + +HRESULT WINAPI QAxServerBase::ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow) +{ + return S_OK; +} + +HRESULT WINAPI QAxServerBase::EnableModeless(BOOL fEnable) +{ + if (!isWidget) + return S_OK; + + EnableWindow(qt.widget->winId(), fEnable); + return S_OK; +} + +//**** IOleObject + +static inline LPOLESTR QStringToOLESTR(const QString &qstring) +{ + LPOLESTR olestr = (wchar_t*)CoTaskMemAlloc(qstring.length()*2+2); + memcpy(olestr, (ushort*)qstring.unicode(), qstring.length()*2); + olestr[qstring.length()] = 0; + return olestr; +} + +/* + \reimp + + See documentation of IOleObject::GetUserType. +*/ +HRESULT WINAPI QAxServerBase::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType) +{ + if (!pszUserType) + return E_POINTER; + + switch (dwFormOfType) { + case USERCLASSTYPE_FULL: + *pszUserType = QStringToOLESTR(class_name); + break; + case USERCLASSTYPE_SHORT: + if (!qt.widget || !isWidget || qt.widget->windowTitle().isEmpty()) + *pszUserType = QStringToOLESTR(class_name); + else + *pszUserType = QStringToOLESTR(qt.widget->windowTitle()); + break; + case USERCLASSTYPE_APPNAME: + *pszUserType = QStringToOLESTR(qApp->objectName()); + break; + } + + return S_OK; +} + +/* + Returns the status flags registered for this control. +*/ +HRESULT WINAPI QAxServerBase::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus) +{ + return OleRegGetMiscStatus(qAxFactory()->classID(class_name), dwAspect, pdwStatus); +} + +/* + Stores the provided advise sink. +*/ +HRESULT WINAPI QAxServerBase::Advise(IAdviseSink* pAdvSink, DWORD* pdwConnection) +{ + *pdwConnection = adviseSinks.count() + 1; + STATDATA data = { {0, 0, DVASPECT_CONTENT, -1, TYMED_NULL} , 0, pAdvSink, *pdwConnection }; + adviseSinks.append(data); + pAdvSink->AddRef(); + return S_OK; +} + +/* + Closes the control. +*/ +HRESULT WINAPI QAxServerBase::Close(DWORD dwSaveOption) +{ + if (dwSaveOption != OLECLOSE_NOSAVE && m_spClientSite) + m_spClientSite->SaveObject(); + if (isInPlaceActive) { + HRESULT hr = InPlaceDeactivate(); + if (FAILED(hr)) + return hr; + } + if (m_hWnd) { + if (IsWindow(m_hWnd)) + DestroyWindow(m_hWnd); + m_hWnd = 0; + if (m_spClientSite) + m_spClientSite->OnShowWindow(false); + } + + if (m_spInPlaceSite) m_spInPlaceSite->Release(); + m_spInPlaceSite = 0; + + if (m_spAdviseSink) + m_spAdviseSink->OnClose(); + for (int i = 0; i < adviseSinks.count(); ++i) { + adviseSinks.at(i).pAdvSink->OnClose(); + } + + return S_OK; +} + +bool qax_disable_inplaceframe = true; + +/* + Executes the steps to activate the control. +*/ +HRESULT QAxServerBase::internalActivate() +{ + if (!m_spClientSite) + return S_OK; + if (!m_spInPlaceSite) + m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void**)&m_spInPlaceSite); + if (!m_spInPlaceSite) + return E_FAIL; + + HRESULT hr = E_FAIL; + if (!isInPlaceActive) { + BOOL bNoRedraw = false; + hr = m_spInPlaceSite->CanInPlaceActivate(); + if (FAILED(hr)) + return hr; + if (hr != S_OK) + return E_FAIL; + m_spInPlaceSite->OnInPlaceActivate(); + } + + isInPlaceActive = true; + OnAmbientPropertyChange(DISPID_AMBIENT_USERMODE); + + if (isWidget) { + IOleInPlaceUIWindow *spInPlaceUIWindow = 0; + HWND hwndParent; + if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) { + // get location in the parent window, as well as some information about the parent + if (m_spInPlaceFrame) m_spInPlaceFrame->Release(); + m_spInPlaceFrame = 0; + RECT rcPos, rcClip; + OLEINPLACEFRAMEINFO frameInfo; + frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); + m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo); + if (m_hWnd) { + ::ShowWindow(m_hWnd, SW_SHOW); + if (!::IsChild(m_hWnd, ::GetFocus()) && qt.widget->focusPolicy() != Qt::NoFocus) + ::SetFocus(m_hWnd); + } else { + create(hwndParent, rcPos); + } + } + + // Gone active by now, take care of UIACTIVATE + canTakeFocus = qt.widget->focusPolicy() != Qt::NoFocus && !inDesignMode; + if (!canTakeFocus && !inDesignMode) { + QList<QWidget*> widgets = qt.widget->findChildren<QWidget*>(); + for (int w = 0; w < widgets.count(); ++w) { + QWidget *widget = widgets[w]; + canTakeFocus = widget->focusPolicy() != Qt::NoFocus; + if (canTakeFocus) + break; + } + } + if (!isUIActive && canTakeFocus) { + isUIActive = true; + hr = m_spInPlaceSite->OnUIActivate(); + if (FAILED(hr)) { + if (m_spInPlaceFrame) m_spInPlaceFrame->Release(); + m_spInPlaceFrame = 0; + if (spInPlaceUIWindow) spInPlaceUIWindow->Release(); + return hr; + } + + if (isInPlaceActive) { + if (!::IsChild(m_hWnd, ::GetFocus())) + ::SetFocus(m_hWnd); + } + + if (m_spInPlaceFrame) { + hr = m_spInPlaceFrame->SetActiveObject(this, QStringToBSTR(class_name)); + if (!FAILED(hr)) { + menuBar = (qt.widget && !qax_disable_inplaceframe) ? qt.widget->findChild<QMenuBar*>() : 0; + if (menuBar && !menuBar->isVisible()) { + createMenu(menuBar); + menuBar->hide(); + menuBar->installEventFilter(this); + } + statusBar = qt.widget ? qt.widget->findChild<QStatusBar*>() : 0; + if (statusBar && !statusBar->isVisible()) { + const int index = statusBar->metaObject()->indexOfSignal("messageChanged(QString)"); + QMetaObject::connect(statusBar, index, this, -1); + statusBar->hide(); + statusBar->installEventFilter(this); + } + } + } + if (spInPlaceUIWindow) { + spInPlaceUIWindow->SetActiveObject(this, QStringToBSTR(class_name)); + spInPlaceUIWindow->SetBorderSpace(0); + } + } + if (spInPlaceUIWindow) spInPlaceUIWindow->Release(); + ShowWindow(m_hWnd, SW_NORMAL); + } + + m_spClientSite->ShowObject(); + + return S_OK; +} + +/* + Executes the "verb" \a iVerb. +*/ +HRESULT WINAPI QAxServerBase::DoVerb(LONG iVerb, LPMSG /*lpmsg*/, IOleClientSite* /*pActiveSite*/, LONG /*lindex*/, + HWND /*hwndParent*/, LPCRECT /*prcPosRect*/) +{ + HRESULT hr = E_NOTIMPL; + switch (iVerb) + { + case OLEIVERB_SHOW: + hr = internalActivate(); + if (SUCCEEDED(hr)) + hr = S_OK; + break; + + case OLEIVERB_PRIMARY: + case OLEIVERB_INPLACEACTIVATE: + hr = internalActivate(); + if (SUCCEEDED(hr)) { + hr = S_OK; + update(); + } + break; + + case OLEIVERB_UIACTIVATE: + if (!isUIActive) { + hr = internalActivate(); + if (SUCCEEDED(hr)) + hr = S_OK; + } + break; + + case OLEIVERB_HIDE: + UIDeactivate(); + if (m_hWnd) + ::ShowWindow(m_hWnd, SW_HIDE); + hr = S_OK; + return hr; + + default: + break; + } + return hr; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::EnumAdvise(IEnumSTATDATA** /*ppenumAdvise*/) +{ + return E_NOTIMPL; +} + +/* + Returns an enumerator for the verbs registered for this class. +*/ +HRESULT WINAPI QAxServerBase::EnumVerbs(IEnumOLEVERB** ppEnumOleVerb) +{ + if (!ppEnumOleVerb) + return E_POINTER; + return OleRegEnumVerbs(qAxFactory()->classID(class_name), ppEnumOleVerb); +} + +/* + Returns the current client site.. +*/ +HRESULT WINAPI QAxServerBase::GetClientSite(IOleClientSite** ppClientSite) +{ + if (!ppClientSite) + return E_POINTER; + *ppClientSite = m_spClientSite; + if (*ppClientSite) + (*ppClientSite)->AddRef(); + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::GetClipboardData(DWORD, IDataObject**) +{ + return E_NOTIMPL; +} + +/* + Returns the current extent. +*/ +HRESULT WINAPI QAxServerBase::GetExtent(DWORD dwDrawAspect, SIZEL* psizel) +{ + if (dwDrawAspect != DVASPECT_CONTENT || !isWidget || !qt.widget) + return E_FAIL; + if (!psizel) + return E_POINTER; + + psizel->cx = MAP_PIX_TO_LOGHIM(m_currentExtent.width(), qt.widget->logicalDpiX()); + psizel->cy = MAP_PIX_TO_LOGHIM(m_currentExtent.height(), qt.widget->logicalDpiY()); + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::GetMoniker(DWORD, DWORD, IMoniker** ) +{ + return E_NOTIMPL; +} + +/* + Returns the CLSID of this class. +*/ +HRESULT WINAPI QAxServerBase::GetUserClassID(CLSID* pClsid) +{ + if (!pClsid) + return E_POINTER; + *pClsid = qAxFactory()->classID(class_name); + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::InitFromData(IDataObject*, BOOL, DWORD) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::IsUpToDate() +{ + return S_OK; +} + +/* + Stores the client site. +*/ +HRESULT WINAPI QAxServerBase::SetClientSite(IOleClientSite* pClientSite) +{ + // release all client site interfaces + if (m_spClientSite) m_spClientSite->Release(); + if (m_spInPlaceSite) m_spInPlaceSite->Release(); + m_spInPlaceSite = 0; + if (m_spInPlaceFrame) m_spInPlaceFrame->Release(); + m_spInPlaceFrame = 0; + + m_spClientSite = pClientSite; + if (m_spClientSite) { + m_spClientSite->AddRef(); + m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_spInPlaceSite); + } + + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::SetColorScheme(LOGPALETTE*) +{ + return E_NOTIMPL; +} + + +#ifdef QT_DLL // avoid conflict with symbol in static lib +bool qt_sendSpontaneousEvent(QObject *o, QEvent *e) +{ + return QCoreApplication::sendSpontaneousEvent(o, e); +} +#endif + +/* + Tries to set the size of the control. +*/ +HRESULT WINAPI QAxServerBase::SetExtent(DWORD dwDrawAspect, SIZEL* psizel) +{ + if (dwDrawAspect != DVASPECT_CONTENT) + return DV_E_DVASPECT; + if (!psizel) + return E_POINTER; + + if (!isWidget || !qt.widget) // nothing to do + return S_OK; + + QSize proposedSize(MAP_LOGHIM_TO_PIX(psizel->cx, qt.widget->logicalDpiX()), + MAP_LOGHIM_TO_PIX(psizel->cy, qt.widget->logicalDpiY())); + + // can the widget be resized at all? + if (qt.widget->minimumSize() == qt.widget->maximumSize() && qt.widget->minimumSize() != proposedSize) + return E_FAIL; + //Save the extent, bound to the widget restrictions. + m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), proposedSize.width(), qt.widget->maximumWidth()); + m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), proposedSize.height(), qt.widget->maximumHeight()); + + resize(proposedSize); + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj) +{ + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::SetMoniker(DWORD, IMoniker*) +{ + return E_NOTIMPL; +} + +/* + Disconnects an advise sink. +*/ +HRESULT WINAPI QAxServerBase::Unadvise(DWORD dwConnection) +{ + for (int i = 0; i < adviseSinks.count(); ++i) { + STATDATA entry = adviseSinks.at(i); + if (entry.dwConnection == dwConnection) { + entry.pAdvSink->Release(); + adviseSinks.removeAt(i); + return S_OK; + } + } + return OLE_E_NOCONNECTION; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::Update() +{ + return S_OK; +} + +//**** IDataObject +/* + Calls IViewObject::Draw after setting up the parameters. +*/ +HRESULT WINAPI QAxServerBase::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) +{ + if (!pmedium) + return E_POINTER; + if ((pformatetcIn->tymed & TYMED_MFPICT) == 0) + return DATA_E_FORMATETC; + + internalCreate(); + if (!isWidget || !qt.widget) + return E_UNEXPECTED; + + // Container wants to draw, but the size is not defined yet - ask container + if (m_spInPlaceSite && !qt.widget->testAttribute(Qt::WA_Resized)) { + IOleInPlaceUIWindow *spInPlaceUIWindow = 0; + RECT rcPos, rcClip; + OLEINPLACEFRAMEINFO frameInfo; + frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); + + HRESULT hres = m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo); + if (hres == S_OK) { + QSize size(rcPos.right - rcPos.left, rcPos.bottom - rcPos.top); + resize(size); + } else { + qt.widget->adjustSize(); + } + if (spInPlaceUIWindow) spInPlaceUIWindow->Release(); // no need for it + } + + int width = qt.widget->width(); + int height = qt.widget->height(); + RECTL rectl = {0, 0, width, height}; + + HDC hdc = CreateMetaFile(0); + SaveDC(hdc); + SetWindowOrgEx(hdc, 0, 0, 0); + SetWindowExtEx(hdc, rectl.right, rectl.bottom, 0); + + Draw(pformatetcIn->dwAspect, pformatetcIn->lindex, 0, pformatetcIn->ptd, 0, hdc, &rectl, &rectl, 0, 0); + + RestoreDC(hdc, -1); + HMETAFILE hMF = CloseMetaFile(hdc); + if (!hMF) + return E_UNEXPECTED; + + HGLOBAL hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT)); + if (!hMem) { + DeleteMetaFile(hMF); + return ResultFromScode(STG_E_MEDIUMFULL); + } + + LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMem); + pMF->hMF = hMF; + pMF->mm = MM_ANISOTROPIC; + pMF->xExt = MAP_PIX_TO_LOGHIM(width, qt.widget->logicalDpiX()); + pMF->yExt = MAP_PIX_TO_LOGHIM(height, qt.widget->logicalDpiY()); + GlobalUnlock(hMem); + + memset(pmedium, 0, sizeof(STGMEDIUM)); + pmedium->tymed = TYMED_MFPICT; + pmedium->hGlobal = hMem; + pmedium->pUnkForRelease = 0; + + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::DAdvise(FORMATETC *pformatetc, DWORD advf, + IAdviseSink *pAdvSink, DWORD *pdwConnection) +{ + if (pformatetc->dwAspect != DVASPECT_CONTENT) + return E_FAIL; + + *pdwConnection = adviseSinks.count() + 1; + STATDATA data = { + {pformatetc->cfFormat,pformatetc->ptd,pformatetc->dwAspect,pformatetc->lindex,pformatetc->tymed}, + advf, pAdvSink, *pdwConnection + }; + adviseSinks.append(data); + pAdvSink->AddRef(); + return S_OK; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::DUnadvise(DWORD dwConnection) +{ + return Unadvise(dwConnection); +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::EnumDAdvise(IEnumSTATDATA ** /*ppenumAdvise*/) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::GetDataHere(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::QueryGetData(FORMATETC* /* pformatetc */) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::GetCanonicalFormatEtc(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::SetData(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */) +{ + return E_NOTIMPL; +} + +/* + Not implemented. +*/ +HRESULT WINAPI QAxServerBase::EnumFormatEtc(DWORD /* dwDirection */, IEnumFORMATETC** /* ppenumFormatEtc */) +{ + return E_NOTIMPL; +} + + + +static int mapModifiers(int state) +{ + int ole = 0; + if (state & Qt::ShiftModifier) + ole |= 1; + if (state & Qt::ControlModifier) + ole |= 2; + if (state & Qt::AltModifier) + ole |= 4; + + return ole; +} + +/* + \reimp +*/ +bool QAxServerBase::eventFilter(QObject *o, QEvent *e) +{ + if (!theObject) + return QObject::eventFilter(o, e); + + if ((e->type() == QEvent::Show || e->type() == QEvent::Hide) && (o == statusBar || o == menuBar)) { + if (o == menuBar) { + if (e->type() == QEvent::Hide) { + createMenu(menuBar); + } else if (e->type() == QEvent::Show) { + removeMenu(); + } + } else if (statusBar) { + statusBar->setSizeGripEnabled(false); + } + updateGeometry(); + if (m_spInPlaceSite && qt.widget->sizeHint().isValid()) { + RECT rect = {0, 0, qt.widget->sizeHint().width(), qt.widget->sizeHint().height()}; + m_spInPlaceSite->OnPosRectChange(&rect); + } + } + switch (e->type()) { + case QEvent::ChildAdded: + static_cast<QChildEvent*>(e)->child()->installEventFilter(this); + break; + case QEvent::ChildRemoved: + static_cast<QChildEvent*>(e)->child()->removeEventFilter(this); + break; + case QEvent::KeyPress: + if (o == qt.object && hasStockEvents) { + QKeyEvent *ke = (QKeyEvent*)e; + int key = ke->key(); + int state = ke->modifiers(); + void *argv[] = { + 0, + &key, + &state + }; + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYDOWN, argv); + if (!ke->text().isEmpty()) + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYPRESS, argv); + } + break; + case QEvent::KeyRelease: + if (o == qt.object && hasStockEvents) { + QKeyEvent *ke = (QKeyEvent*)e; + int key = ke->key(); + int state = ke->modifiers(); + void *argv[] = { + 0, + &key, + &state + }; + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYUP, argv); + } + break; + case QEvent::MouseMove: + if (o == qt.object && hasStockEvents) { + QMouseEvent *me = (QMouseEvent*)e; + int button = me->buttons() & Qt::MouseButtonMask; + int state = mapModifiers(me->modifiers()); + int x = me->x(); + int y = me->y(); + void *argv[] = { + 0, + &button, + &state, + &x, + &y + }; + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEMOVE, argv); + } + break; + case QEvent::MouseButtonRelease: + if (o == qt.object && hasStockEvents) { + QMouseEvent *me = (QMouseEvent*)e; + int button = me->button(); + int state = mapModifiers(me->modifiers()); + int x = me->x(); + int y = me->y(); + void *argv[] = { + 0, + &button, + &state, + &x, + &y + }; + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEUP, argv); + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_CLICK, 0); + } + break; + case QEvent::MouseButtonDblClick: + if (o == qt.object && hasStockEvents) { + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_DBLCLICK, 0); + } + break; + case QEvent::MouseButtonPress: + if (m_spInPlaceSite && !isUIActive) { + internalActivate(); + } + if (o == qt.widget && hasStockEvents) { + QMouseEvent *me = (QMouseEvent*)e; + int button = me->button(); + int state = mapModifiers(me->modifiers()); + int x = me->x(); + int y = me->y(); + void *argv[] = { + 0, + &button, + &state, + &x, + &y + }; + qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEDOWN, argv); + } + break; + case QEvent::Show: + if (m_hWnd && o == qt.widget) + ShowWindow(m_hWnd, SW_SHOW); + updateMask(); + break; + case QEvent::Hide: + if (m_hWnd && o == qt.widget) + ShowWindow(m_hWnd, SW_HIDE); + break; + + case QEvent::EnabledChange: + if (m_hWnd && o == qt.widget) + EnableWindow(m_hWnd, qt.widget->isEnabled()); + // Fall Through + case QEvent::FontChange: + case QEvent::ActivationChange: + case QEvent::StyleChange: + case QEvent::IconTextChange: + case QEvent::ModifiedChange: + case QEvent::Resize: + updateMask(); + break; + case QEvent::WindowBlocked: { + if (!m_spInPlaceFrame) + break; + m_spInPlaceFrame->EnableModeless(FALSE); + MSG msg; + // Visual Basic 6.0 posts the message WM_USER+3078 from the EnableModeless(). + // While handling this message, VB will disable all current top-levels. After + // this we have to re-enable the Qt modal widget to receive input events. + if (PeekMessage(&msg, 0, WM_USER+3078, WM_USER+3078, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + QWidget *modalWidget = QApplication::activeModalWidget(); + if (modalWidget && modalWidget->isVisible() && modalWidget->isEnabled() + && !IsWindowEnabled(modalWidget->effectiveWinId())) + EnableWindow(modalWidget->effectiveWinId(), TRUE); + } + break; + } + case QEvent::WindowUnblocked: + if (!m_spInPlaceFrame) + break; + m_spInPlaceFrame->EnableModeless(TRUE); + break; + default: + break; + } + return QObject::eventFilter(o, e); +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/control/qaxserverdll.cpp b/src/activeqt/control/qaxserverdll.cpp new file mode 100644 index 0000000..22c01d8 --- /dev/null +++ b/src/activeqt/control/qaxserverdll.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qapplication.h> +#include <qwidget.h> + +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +bool qax_ownQApp = false; +HHOOK qax_hhook = 0; + +// in qaxserver.cpp +extern wchar_t qAxModuleFilename[MAX_PATH]; +extern bool qAxIsServer; +extern ITypeLib *qAxTypeLibrary; +extern unsigned long qAxLockCount(); +extern QString qAxInit(); +extern void qAxCleanup(); +extern HANDLE qAxInstance; +static uint qAxThreadId = 0; + +extern HRESULT UpdateRegistry(int bRegister); +extern HRESULT GetClassObject(const GUID &clsid, const GUID &iid, void **ppUnk); + +STDAPI DllRegisterServer() +{ + return UpdateRegistry(true); +} + +STDAPI DllUnregisterServer() +{ + return UpdateRegistry(false); +} + +STDAPI DllGetClassObject(const GUID &clsid, const GUID &iid, void** ppv) +{ + if (!qAxThreadId) + qAxThreadId = GetCurrentThreadId(); + else if (GetCurrentThreadId() != qAxThreadId) + return E_FAIL; + + GetClassObject(clsid, iid, ppv); + if (!*ppv) + return CLASS_E_CLASSNOTAVAILABLE; + return S_OK; +} + +STDAPI DllCanUnloadNow() +{ + if (GetCurrentThreadId() != qAxThreadId) + return S_FALSE; + if (qAxLockCount()) + return S_FALSE; + if (!qax_ownQApp) + return S_OK; + + // check if qApp still runs widgets (in other DLLs) + QWidgetList widgets = qApp->allWidgets(); + int count = widgets.count(); + for (int w = 0; w < widgets.count(); ++w) { + // remove all Qt generated widgets + QWidget *widget = widgets.at(w); + if (widget->windowType() == Qt::Desktop || widget->objectName() == QLatin1String("Qt internal tablet widget")) + count--; + } + if (count) + return S_FALSE; + + // no widgets left - destroy qApp + if (qax_hhook) + UnhookWindowsHookEx(qax_hhook); + + delete qApp; + qax_ownQApp = false; + + // never allow unloading - safety net for Internet Explorer + return S_FALSE; +} + + +EXTERN_C BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved) +{ + GetModuleFileName(hInstance, qAxModuleFilename, MAX_PATH); + qAxInstance = hInstance; + qAxIsServer = true; + + if (dwReason == DLL_PROCESS_ATTACH) { + DisableThreadLibraryCalls(hInstance); + qAxInit(); + } else if (dwReason == DLL_PROCESS_DETACH) { + qAxCleanup(); + } + + return true; +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/control/qaxservermain.cpp b/src/activeqt/control/qaxservermain.cpp new file mode 100644 index 0000000..43ec8cd --- /dev/null +++ b/src/activeqt/control/qaxservermain.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qstringlist.h> +#include <qvector.h> + +#include "qaxfactory.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +static DWORD *classRegistration = 0; +static DWORD dwThreadID; +static bool qAxActivity = false; +static HANDLE hEventShutdown; + +#ifdef QT_DEBUG +QT_STATIC_CONST DWORD dwTimeOut = 1000; +QT_STATIC_CONST DWORD dwPause = 500; +#else +QT_STATIC_CONST DWORD dwTimeOut = 5000; // time for EXE to be idle before shutting down +QT_STATIC_CONST DWORD dwPause = 1000; // time to wait for threads to finish up +#endif + +extern HANDLE hEventShutdown; +extern bool qAxActivity; +extern HANDLE qAxInstance; +extern bool qAxIsServer; +extern bool qAxOutProcServer; +extern wchar_t qAxModuleFilename[MAX_PATH]; +extern QString qAxInit(); +extern void qAxCleanup(); +extern HRESULT UpdateRegistry(BOOL bRegister); +extern HRESULT GetClassObject(const GUID &clsid, const GUID &iid, void **ppUnk); +extern ulong qAxLockCount(); +extern bool qax_winEventFilter(void *message); + +#if defined(Q_CC_BOR) +extern "C" __stdcall HRESULT DumpIDL(const QString &outfile, const QString &ver); +#else +STDAPI DumpIDL(const QString &outfile, const QString &ver); +#endif + +// Monitors the shutdown event +static DWORD WINAPI MonitorProc(void* pv) +{ + while (1) { + WaitForSingleObject(hEventShutdown, INFINITE); + DWORD dwWait=0; + do { + qAxActivity = false; + dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut); + } while (dwWait == WAIT_OBJECT_0); + // timed out + if (!qAxActivity && !qAxLockCount()) // if no activity let's really bail + break; + } + CloseHandle(hEventShutdown); + PostThreadMessage(dwThreadID, WM_QUIT, 0, 0); + PostQuitMessage(0); + + return 0; +} + +// Starts the monitoring thread +static bool StartMonitor() +{ + dwThreadID = GetCurrentThreadId(); + hEventShutdown = CreateEvent(0, false, false, 0); + if (hEventShutdown == 0) + return false; + DWORD dwThreadID; + HANDLE h = CreateThread(0, 0, MonitorProc, 0, 0, &dwThreadID); + return (h != NULL); +} + +void qax_shutDown() +{ + qAxActivity = true; + if (hEventShutdown) + SetEvent(hEventShutdown); // tell monitor that we transitioned to zero +} + +/* + Start the COM server (if necessary). +*/ +bool qax_startServer(QAxFactory::ServerType type) +{ + if (qAxIsServer) + return true; + + const QStringList keys = qAxFactory()->featureList(); + if (!keys.count()) + return false; + + if (!qAxFactory()->isService()) + StartMonitor(); + + classRegistration = new DWORD[keys.count()]; + int object = 0; + for (QStringList::ConstIterator key = keys.begin(); key != keys.end(); ++key, ++object) { + IUnknown* p = 0; + CLSID clsid = qAxFactory()->classID(*key); + + // Create a QClassFactory (implemented in qaxserverbase.cpp) + HRESULT hRes = GetClassObject(clsid, IID_IClassFactory, (void**)&p); + if (SUCCEEDED(hRes)) + hRes = CoRegisterClassObject(clsid, p, CLSCTX_LOCAL_SERVER, + type == QAxFactory::MultipleInstances ? REGCLS_MULTIPLEUSE : REGCLS_SINGLEUSE, + classRegistration+object); + if (p) + p->Release(); + } + + qAxIsServer = true; + return true; +} + +/* + Stop the COM server (if necessary). +*/ +bool qax_stopServer() +{ + if (!qAxIsServer || !classRegistration) + return true; + + qAxIsServer = false; + + const QStringList keys = qAxFactory()->featureList(); + int object = 0; + for (QStringList::ConstIterator key = keys.begin(); key != keys.end(); ++key, ++object) + CoRevokeClassObject(classRegistration[object]); + + delete []classRegistration; + classRegistration = 0; + + Sleep(dwPause); //wait for any threads to finish + + return true; +} + +#if defined(Q_OS_WINCE) +extern void __cdecl qWinMain(HINSTANCE, HINSTANCE, LPSTR, int, int &, QVector<char *> &); +#else +extern void qWinMain(HINSTANCE, HINSTANCE, LPSTR, int, int &, QVector<char *> &); +#endif + +QT_END_NAMESPACE + +#if defined(QT_NEEDS_QMAIN) +int qMain(int, char **); +#define main qMain +#else +#if defined(Q_OS_WINCE) +extern "C" int __cdecl main(int, char **); +#else +extern "C" int main(int, char **); +#endif +#endif + + +EXTERN_C int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nShowCmd) +{ + QT_USE_NAMESPACE + + qAxOutProcServer = true; + GetModuleFileName(0, qAxModuleFilename, MAX_PATH); + qAxInstance = hInstance; + + QByteArray cmdParam = QString::fromWCharArray(GetCommandLine()).toLocal8Bit(); + QList<QByteArray> cmds = cmdParam.split(' '); + QByteArray unprocessed; + + int nRet = 0; + bool run = true; + bool runServer = false; + for (int i = 0; i < cmds.count(); ++i) { + QByteArray cmd = cmds.at(i).toLower(); + if (cmd == "-activex" || cmd == "/activex" || cmd == "-embedding" || cmd == "/embedding") { + runServer = true; + } else if (cmd == "-unregserver" || cmd == "/unregserver") { + nRet = UpdateRegistry(false); + run = false; + break; + } else if (cmd == "-regserver" || cmd == "/regserver") { + nRet = UpdateRegistry(true); + run = false; + break; + } else if (cmd == "-dumpidl" || cmd == "/dumpidl") { + ++i; + if (i < cmds.count()) { + QByteArray outfile = cmds.at(i); + ++i; + QByteArray version; + if (i < cmds.count() && (cmds.at(i) == "-version" || cmds.at(i) == "/version")) { + ++i; + if (i < cmds.count()) + version = cmds.at(i); + else + version = "1.0"; + } + + nRet = DumpIDL(QString::fromLatin1(outfile.constData()), QString::fromLatin1(version.constData())); + } else { + qWarning("Wrong commandline syntax: <app> -dumpidl <idl file> [-version <x.y.z>]"); + } + run = false; + break; + } else { + unprocessed += cmds.at(i) + ' '; + } + } + + if (run) { + HRESULT hRes = CoInitialize(0); + + int argc; + QVector<char*> argv(8); + qWinMain(hInstance, hPrevInstance, unprocessed.data(), nShowCmd, argc, argv); + qAxInit(); + if (runServer) + QAxFactory::startServer(); + nRet = ::main(argc, argv.data()); + QAxFactory::stopServer(); + qAxCleanup(); + CoUninitialize(); + + } + + return nRet; +} + +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/shared/qaxtypes.cpp b/src/activeqt/shared/qaxtypes.cpp new file mode 100644 index 0000000..c48b55b --- /dev/null +++ b/src/activeqt/shared/qaxtypes.cpp @@ -0,0 +1,1484 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <ocidl.h> +#include <olectl.h> + +#include "qaxtypes.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qcolormap.h> +#include <qcursor.h> +#include <qpixmap.h> +#include <qpainter.h> +#include <qobject.h> +#ifdef QAX_SERVER +# include <qaxfactory.h> +# include <private/qsystemlibrary_p.h> +#else +# include <quuid.h> +# include <qaxobject.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef QAX_SERVER +extern ITypeLib *qAxTypeLibrary; + +CLSID CLSID_QRect = { 0x34030f30, 0xe359, 0x4fe6, {0xab, 0x82, 0x39, 0x76, 0x6f, 0x5d, 0x91, 0xee } }; +CLSID CLSID_QSize = { 0xcb5f84b3, 0x29e5, 0x491d, {0xba, 0x18, 0x54, 0x72, 0x48, 0x8e, 0xef, 0xba } }; +CLSID CLSID_QPoint = { 0x3be838a3, 0x3fac, 0xbfc4, {0x4c, 0x6c, 0x37, 0xc4, 0x4d, 0x03, 0x02, 0x52 } }; + +GUID IID_IAxServerBase = { 0xbd2ec165, 0xdfc9, 0x4319, { 0x8b, 0x9b, 0x60, 0xa5, 0x74, 0x78, 0xe9, 0xe3} }; +#else +extern void *qax_createObjectWrapper(int metaType, IUnknown *iface); +#endif + +static IFontDisp *QFontToIFont(const QFont &font) +{ +#if defined(Q_OS_WINCE) + Q_UNUSED(font); + return 0; +#else + FONTDESC fdesc; + memset(&fdesc, 0, sizeof(fdesc)); + fdesc.cbSizeofstruct = sizeof(FONTDESC); + fdesc.cySize.Lo = font.pointSize() * 10000; + fdesc.fItalic = font.italic(); + fdesc.fStrikethrough = font.strikeOut(); + fdesc.fUnderline = font.underline(); + fdesc.lpstrName = QStringToBSTR(font.family()); + fdesc.sWeight = font.weight() * 10; + + IFontDisp *f; + HRESULT res = OleCreateFontIndirect(&fdesc, IID_IFontDisp, (void**)&f); + if (res != S_OK) { + if (f) f->Release(); + f = 0; +#if defined(QT_CHECK_STATE) + qWarning("QFontToIFont: Failed to create IFont"); +#endif + } + return f; +#endif +} + +static QFont IFontToQFont(IFont *f) +{ + BSTR name; + BOOL bold; + SHORT charset; + BOOL italic; + CY size; + BOOL strike; + BOOL underline; + SHORT weight; + f->get_Name(&name); + f->get_Bold(&bold); + f->get_Charset(&charset); + f->get_Italic(&italic); + f->get_Size(&size); + f->get_Strikethrough(&strike); + f->get_Underline(&underline); + f->get_Weight(&weight); + QFont font(QString::fromWCharArray(name), size.Lo/9750, weight / 97, italic); + font.setBold(bold); + font.setStrikeOut(strike); + font.setUnderline(underline); + SysFreeString(name); + + return font; +} + +static IPictureDisp *QPixmapToIPicture(const QPixmap &pixmap) +{ +#if defined(Q_OS_WINCE) + Q_UNUSED(pixmap); + return 0; +#else + IPictureDisp *pic = 0; + + PICTDESC desc; + desc.cbSizeofstruct = sizeof(PICTDESC); + desc.picType = PICTYPE_BITMAP; + + desc.bmp.hbitmap = 0; + desc.bmp.hpal = QColormap::hPal(); + + if (!pixmap.isNull()) { + desc.bmp.hbitmap = pixmap.toWinHBITMAP(); + Q_ASSERT(desc.bmp.hbitmap); + } + + HRESULT res = OleCreatePictureIndirect(&desc, IID_IPictureDisp, true, (void**)&pic); + if (res != S_OK) { + if (pic) pic->Release(); + pic = 0; +#if defined(QT_CHECK_STATE) + qWarning("QPixmapToIPicture: Failed to create IPicture"); +#endif + } + return pic; +#endif +} + +static QPixmap IPictureToQPixmap(IPicture *ipic) +{ + SHORT type; + ipic->get_Type(&type); + if (type != PICTYPE_BITMAP) + return QPixmap(); + + HBITMAP hbm = 0; + ipic->get_Handle((OLE_HANDLE*)&hbm); + if (!hbm) + return QPixmap(); + + return QPixmap::fromWinHBITMAP(hbm); +} + +static QDateTime DATEToQDateTime(DATE ole) +{ + SYSTEMTIME stime; + if (ole >= 949998 || VariantTimeToSystemTime(ole, &stime) == false) + return QDateTime(); + + QDate date(stime.wYear, stime.wMonth, stime.wDay); + QTime time(stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds); + return QDateTime(date, time); +} + +static DATE QDateTimeToDATE(const QDateTime &dt) +{ + if (!dt.isValid() || dt.isNull()) + return 949998; + + SYSTEMTIME stime; + memset(&stime, 0, sizeof(stime)); + QDate date = dt.date(); + QTime time = dt.time(); + if (date.isValid() && !date.isNull()) { + stime.wDay = date.day(); + stime.wMonth = date.month(); + stime.wYear = date.year(); + } + if (time.isValid() && !time.isNull()) { + stime.wMilliseconds = time.msec(); + stime.wSecond = time.second(); + stime.wMinute = time.minute(); + stime.wHour = time.hour(); + } + + double vtime; + SystemTimeToVariantTime(&stime, &vtime); + + return vtime; +} + +QColor OLEColorToQColor(uint col) +{ +#if defined(Q_OS_WINCE) + return QColor(GetBValue(col),GetGValue(col),GetRValue(col)); +#else + COLORREF cref; + OleTranslateColor(col, QColormap::hPal(), &cref); + return QColor(GetRValue(cref),GetGValue(cref),GetBValue(cref)); +#endif +} + +/* + Converts \a var to \a arg, and tries to coerce \a arg to \a type. + + Used by + + QAxServerBase: + - QAxServerBase::qt_metacall + - IDispatch::Invoke(PROPERTYGET, METHOD) + - IPersistPropertyBag::Save + + QAxBase: + - IDispatch::Invoke (QAxEventSink) + - QAxBase::internalProperty(WriteProperty) + - QAxBase::internalInvoke() + - QAxBase::dynamicCallHelper() + - IPropertyBag::Read (QtPropertyBag) + + Also called recoursively for lists. +*/ +bool QVariantToVARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeName, bool out) +{ + QVariant qvar = var; + // "type" is the expected type, so coerce if necessary + QVariant::Type proptype = typeName.isEmpty() ? QVariant::Invalid : QVariant::nameToType(typeName); + if (proptype == QVariant::UserType && !typeName.isEmpty()) { + if (typeName == "short" || typeName == "char") + proptype = QVariant::Int; + else if (typeName == "float") + proptype = QVariant::Double; + } + if (proptype != QVariant::Invalid && proptype != QVariant::UserType && proptype != qvar.type()) { + if (qvar.canConvert(proptype)) + qvar.convert(proptype); + else + qvar = QVariant(proptype); + } + + if (out && arg.vt == (VT_VARIANT|VT_BYREF) && arg.pvarVal) { + return QVariantToVARIANT(var, *arg.pvarVal, typeName, false); + } + + if (out && proptype == QVariant::Invalid && typeName == "QVariant") { + VARIANT *pVariant = new VARIANT; + QVariantToVARIANT(var, *pVariant, QByteArray(), false); + arg.vt = VT_VARIANT|VT_BYREF; + arg.pvarVal = pVariant; + return true; + } + + switch ((int)qvar.type()) { + case QVariant::String: + if (out && arg.vt == (VT_BSTR|VT_BYREF)) { + if (*arg.pbstrVal) + SysFreeString(*arg.pbstrVal); + *arg.pbstrVal = QStringToBSTR(qvar.toString()); + arg.vt = VT_BSTR|VT_BYREF; + } else { + arg.vt = VT_BSTR; + arg.bstrVal = QStringToBSTR(qvar.toString()); + if (out) { + arg.pbstrVal = new BSTR(arg.bstrVal); + arg.vt |= VT_BYREF; + } + } + break; + + case QVariant::Int: + if (out && arg.vt == (VT_I4|VT_BYREF)) { + *arg.plVal = qvar.toInt(); + } else { + arg.vt = VT_I4; + arg.lVal = qvar.toInt(); + if (out) { + if (typeName == "short") { + arg.vt = VT_I2; + arg.piVal = new short(arg.lVal); + } else if (typeName == "char") { + arg.vt = VT_I1; + arg.pcVal= new char(arg.lVal); + } else { + arg.plVal = new long(arg.lVal); + } + arg.vt |= VT_BYREF; + } + } + break; + + case QVariant::UInt: + if (out && (arg.vt == (VT_UINT|VT_BYREF) || arg.vt == (VT_I4|VT_BYREF))) { + *arg.puintVal = qvar.toUInt(); + } else { + arg.vt = VT_UINT; + arg.uintVal = qvar.toUInt(); + if (out) { + arg.puintVal = new uint(arg.uintVal); + arg.vt |= VT_BYREF; + } + } + break; + + case QVariant::LongLong: + if (out && arg.vt == (VT_CY|VT_BYREF)) { + arg.pcyVal->int64 = qvar.toLongLong(); +#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400 + } else if (out && arg.vt == (VT_I8|VT_BYREF)) { + *arg.pllVal = qvar.toLongLong(); + } else { + arg.vt = VT_I8; + arg.llVal = qvar.toLongLong(); + if (out) { + arg.pllVal = new LONGLONG(arg.llVal); + arg.vt |= VT_BYREF; + } + } +#else + } else { + arg.vt = VT_CY; + arg.cyVal.int64 = qvar.toLongLong(); + if (out) { + arg.pcyVal = new CY(arg.cyVal); + arg.vt |= VT_BYREF; + } + } +#endif + break; + + case QVariant::ULongLong: + if (out && arg.vt == (VT_CY|VT_BYREF)) { + arg.pcyVal->int64 = qvar.toULongLong(); +#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400 + } else if (out && arg.vt == (VT_UI8|VT_BYREF)) { + *arg.pullVal = qvar.toULongLong(); + } else { + arg.vt = VT_UI8; + arg.ullVal = qvar.toULongLong(); + if (out) { + arg.pullVal = new ULONGLONG(arg.ullVal); + arg.vt |= VT_BYREF; + } + } +#else + } else { + arg.vt = VT_CY; + arg.cyVal.int64 = qvar.toULongLong(); + if (out) { + arg.pcyVal = new CY(arg.cyVal); + arg.vt |= VT_BYREF; + } + } + +#endif + + break; + + case QVariant::Bool: + if (out && arg.vt == (VT_BOOL|VT_BYREF)) { + *arg.pboolVal = qvar.toBool() ? VARIANT_TRUE : VARIANT_FALSE; + } else { + arg.vt = VT_BOOL; + arg.boolVal = qvar.toBool() ? VARIANT_TRUE : VARIANT_FALSE; + if (out) { + arg.pboolVal = new short(arg.boolVal); + arg.vt |= VT_BYREF; + } + } + break; + case QVariant::Double: + if (out && arg.vt == (VT_R8|VT_BYREF)) { + *arg.pdblVal = qvar.toDouble(); + } else { + arg.vt = VT_R8; + arg.dblVal = qvar.toDouble(); + if (out) { + if (typeName == "float") { + arg.vt = VT_R4; + arg.pfltVal = new float(arg.dblVal); + } else { + arg.pdblVal = new double(arg.dblVal); + } + arg.vt |= VT_BYREF; + } + } + break; + case QVariant::Color: + if (out && arg.vt == (VT_COLOR|VT_BYREF)) { + + *arg.plVal = QColorToOLEColor(qvariant_cast<QColor>(qvar)); + } else { + arg.vt = VT_COLOR; + arg.lVal = QColorToOLEColor(qvariant_cast<QColor>(qvar)); + if (out) { + arg.plVal = new long(arg.lVal); + arg.vt |= VT_BYREF; + } + } + break; + + case QVariant::Date: + case QVariant::Time: + case QVariant::DateTime: + if (out && arg.vt == (VT_DATE|VT_BYREF)) { + *arg.pdate = QDateTimeToDATE(qvar.toDateTime()); + } else { + arg.vt = VT_DATE; + arg.date = QDateTimeToDATE(qvar.toDateTime()); + if (out) { + arg.pdate = new DATE(arg.date); + arg.vt |= VT_BYREF; + } + } + break; + case QVariant::Font: + if (out && arg.vt == (VT_DISPATCH|VT_BYREF)) { + if (*arg.ppdispVal) + (*arg.ppdispVal)->Release(); + *arg.ppdispVal = QFontToIFont(qvariant_cast<QFont>(qvar)); + } else { + arg.vt = VT_DISPATCH; + arg.pdispVal = QFontToIFont(qvariant_cast<QFont>(qvar)); + if (out) { + arg.ppdispVal = new IDispatch*(arg.pdispVal); + arg.vt |= VT_BYREF; + } + } + break; + + case QVariant::Pixmap: + if (out && arg.vt == (VT_DISPATCH|VT_BYREF)) { + if (*arg.ppdispVal) + (*arg.ppdispVal)->Release(); + *arg.ppdispVal = QPixmapToIPicture(qvariant_cast<QPixmap>(qvar)); + } else { + arg.vt = VT_DISPATCH; + arg.pdispVal = QPixmapToIPicture(qvariant_cast<QPixmap>(qvar)); + if (out) { + arg.ppdispVal = new IDispatch*(arg.pdispVal); + arg.vt |= VT_BYREF; + } + } + break; + + case QVariant::Cursor: + { +#ifndef QT_NO_CURSOR + int shape = qvariant_cast<QCursor>(qvar).shape(); + if (out && (arg.vt & VT_BYREF)) { + switch(arg.vt & ~VT_BYREF) { + case VT_I4: + *arg.plVal = shape; + break; + case VT_I2: + *arg.piVal = shape; + break; + case VT_UI4: + *arg.pulVal = shape; + break; + case VT_UI2: + *arg.puiVal = shape; + break; + case VT_INT: + *arg.pintVal = shape; + break; + case VT_UINT: + *arg.puintVal = shape; + break; + } + } else { + arg.vt = VT_I4; + arg.lVal = shape; + if (out) { + arg.plVal = new long(arg.lVal); + arg.vt |= VT_BYREF; + } + } +#endif + } + break; + + case QVariant::List: + { + const QList<QVariant> list = qvar.toList(); + const int count = list.count(); + VARTYPE vt = VT_VARIANT; + QVariant::Type listType = QVariant::LastType; // == QVariant + if (!typeName.isEmpty() && typeName.startsWith("QList<")) { + const QByteArray listTypeName = typeName.mid(6, typeName.length() - 7); // QList<int> -> int + listType = QVariant::nameToType(listTypeName); + } + + VARIANT variant; + void *pElement = &variant; + switch(listType) { + case QVariant::Int: + vt = VT_I4; + pElement = &variant.lVal; + break; + case QVariant::Double: + vt = VT_R8; + pElement = &variant.dblVal; + break; + case QVariant::DateTime: + vt = VT_DATE; + pElement = &variant.date; + break; + case QVariant::Bool: + vt = VT_BOOL; + pElement = &variant.boolVal; + break; + case QVariant::LongLong: +#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400 + vt = VT_I8; + pElement = &variant.llVal; +#else + vt = VT_CY; + pElement = &variant.cyVal; +#endif + break; + default: + break; + } + SAFEARRAY *array = 0; + bool is2D = false; + // If the first element in the array is a list the whole list is + // treated as a 2D array. The column count is taken from the 1st element. + if (count) { + QVariantList col = list.at(0).toList(); + int maxColumns = col.count(); + if (maxColumns) { + is2D = true; + SAFEARRAYBOUND rgsabound[2] = { {0} }; + rgsabound[0].cElements = count; + rgsabound[1].cElements = maxColumns; + array = SafeArrayCreate(VT_VARIANT, 2, rgsabound); + LONG rgIndices[2]; + for (LONG i = 0; i < count; ++i) { + rgIndices[0] = i; + QVariantList columns = list.at(i).toList(); + int columnCount = qMin(maxColumns, columns.count()); + for (LONG j = 0; j < columnCount; ++j) { + QVariant elem = columns.at(j); + VariantInit(&variant); + QVariantToVARIANT(elem, variant, elem.typeName()); + rgIndices[1] = j; + SafeArrayPutElement(array, rgIndices, pElement); + clearVARIANT(&variant); + } + } + + } + } + if (!is2D) { + array = SafeArrayCreateVector(vt, 0, count); + for (LONG index = 0; index < count; ++index) { + QVariant elem = list.at(index); + if (listType != QVariant::LastType) + elem.convert(listType); + VariantInit(&variant); + QVariantToVARIANT(elem, variant, elem.typeName()); + SafeArrayPutElement(array, &index, pElement); + clearVARIANT(&variant); + } + } + if (out && arg.vt == (VT_ARRAY|vt|VT_BYREF)) { + if (*arg.pparray) + SafeArrayDestroy(*arg.pparray); + *arg.pparray = array; + } else { + arg.vt = VT_ARRAY|vt; + arg.parray = array; + if (out) { + arg.pparray = new SAFEARRAY*(arg.parray); + arg.vt |= VT_BYREF; + } + } + } + break; + + case QVariant::StringList: + { + const QStringList list = qvar.toStringList(); + const int count = list.count(); + SAFEARRAY *array = SafeArrayCreateVector(VT_BSTR, 0, count); + for (LONG index = 0; index < count; ++index) { + QString elem = list.at(index); + BSTR bstr = QStringToBSTR(elem); + SafeArrayPutElement(array, &index, bstr); + SysFreeString(bstr); + } + + if (out && arg.vt == (VT_ARRAY|VT_BSTR|VT_BYREF)) { + if (*arg.pparray) + SafeArrayDestroy(*arg.pparray); + *arg.pparray = array; + } else { + arg.vt = VT_ARRAY|VT_BSTR; + arg.parray = array; + if (out) { + arg.pparray = new SAFEARRAY*(arg.parray); + arg.vt |= VT_BYREF; + } + } + } + break; + + case QVariant::ByteArray: + { + const QByteArray bytes = qvar.toByteArray(); + const uint count = bytes.count(); + SAFEARRAY *array = SafeArrayCreateVector(VT_UI1, 0, count); + if (count) { + const char *data = bytes.constData(); + char *dest; + SafeArrayAccessData(array, (void **)&dest); + memcpy(dest, data, count); + SafeArrayUnaccessData(array); + } + + if (out && arg.vt == (VT_ARRAY|VT_UI1|VT_BYREF)) { + if (*arg.pparray) + SafeArrayDestroy(*arg.pparray); + *arg.pparray = array; + } else { + arg.vt = VT_ARRAY|VT_UI1; + arg.parray = array; + if (out) { + arg.pparray = new SAFEARRAY*(arg.parray); + arg.vt |= VT_BYREF; + } + } + } + break; + +#ifdef QAX_SERVER + case QVariant::Rect: + case QVariant::Size: + case QVariant::Point: + { + typedef HRESULT(WINAPI* PGetRecordInfoFromTypeInfo)(ITypeInfo *, IRecordInfo **); + static PGetRecordInfoFromTypeInfo pGetRecordInfoFromTypeInfo = 0; + static bool resolved = false; + if (!resolved) { + resolved = true; + pGetRecordInfoFromTypeInfo = (PGetRecordInfoFromTypeInfo)QSystemLibrary::resolve(QLatin1String("oleaut32"), + "GetRecordInfoFromTypeInfo"); + } + if (!pGetRecordInfoFromTypeInfo) + break; + + ITypeInfo *typeInfo = 0; + IRecordInfo *recordInfo = 0; + CLSID clsid = qvar.type() == QVariant::Rect ? CLSID_QRect + :qvar.type() == QVariant::Size ? CLSID_QSize + :CLSID_QPoint; + qAxTypeLibrary->GetTypeInfoOfGuid(clsid, &typeInfo); + if (!typeInfo) + break; + pGetRecordInfoFromTypeInfo(typeInfo, &recordInfo); + typeInfo->Release(); + if (!recordInfo) + break; + + void *record = 0; + switch (qvar.type()) { + case QVariant::Rect: + { + QRect qrect(qvar.toRect()); + recordInfo->RecordCreateCopy(&qrect, &record); + } + break; + case QVariant::Size: + { + QSize qsize(qvar.toSize()); + recordInfo->RecordCreateCopy(&qsize, &record); + } + break; + case QVariant::Point: + { + QPoint qpoint(qvar.toPoint()); + recordInfo->RecordCreateCopy(&qpoint, &record); + } + break; + } + + arg.vt = VT_RECORD; + arg.pRecInfo = recordInfo, + arg.pvRecord = record; + if (out) { + qWarning("QVariantToVARIANT: out-parameter not supported for records"); + return false; + } + } + break; +#endif // QAX_SERVER + case QVariant::UserType: + { + QByteArray subType = qvar.typeName(); +#ifdef QAX_SERVER + if (subType.endsWith('*')) + subType.truncate(subType.length() - 1); +#endif + if (!qstrcmp(qvar.typeName(), "IDispatch*")) { + arg.vt = VT_DISPATCH; + arg.pdispVal = *(IDispatch**)qvar.data(); + if (arg.pdispVal) + arg.pdispVal->AddRef(); + if (out) { + qWarning("QVariantToVARIANT: out-parameter not supported for IDispatch"); + return false; + } + } else if (!qstrcmp(qvar.typeName(), "IDispatch**")) { + arg.vt = VT_DISPATCH; + arg.ppdispVal = *(IDispatch***)qvar.data(); + if (out) + arg.vt |= VT_BYREF; + } else if (!qstrcmp(qvar.typeName(), "IUnknown*")) { + arg.vt = VT_UNKNOWN; + arg.punkVal = *(IUnknown**)qvar.data(); + if (arg.punkVal) + arg.punkVal->AddRef(); + if (out) { + qWarning("QVariantToVARIANT: out-parameter not supported for IUnknown"); + return false; + } +#ifdef QAX_SERVER + } else if (qAxFactory()->metaObject(QString::fromLatin1(subType.constData()))) { + arg.vt = VT_DISPATCH; + void *user = *(void**)qvar.constData(); +// qVariantGet(qvar, user, qvar.typeName()); + if (!user) { + arg.pdispVal = 0; + } else { + qAxFactory()->createObjectWrapper(static_cast<QObject*>(user), &arg.pdispVal); + } + if (out) { + qWarning("QVariantToVARIANT: out-parameter not supported for subtype"); + return false; + } +#else + } else if (QMetaType::type(subType)) { + QAxObject *object = *(QAxObject**)qvar.constData(); +// qVariantGet(qvar, object, subType); + arg.vt = VT_DISPATCH; + object->queryInterface(IID_IDispatch, (void**)&arg.pdispVal); + if (out) { + qWarning("QVariantToVARIANT: out-parameter not supported for subtype"); + return false; + } +#endif + } else { + return false; + } + } + break; + case QVariant::Invalid: // default-parameters not set + if (out && arg.vt == (VT_ERROR|VT_BYREF)) { + *arg.plVal = DISP_E_PARAMNOTFOUND; + } else { + arg.vt = VT_ERROR; + arg.lVal = DISP_E_PARAMNOTFOUND; + if (out) { + arg.plVal = new long(arg.lVal); + arg.vt |= VT_BYREF; + } + } + break; + + default: + return false; + } + + Q_ASSERT(!out || (arg.vt & VT_BYREF)); + return true; +} + +/*! + Copies the data in \a var into \a data. + + Used by + + QAxServerBase: + - QAxServerBase::qt_metacall (update out parameters/return value) + + QAxBase: + - internalProperty(ReadProperty) + - internalInvoke(update out parameters/return value) + +*/ +bool QVariantToVoidStar(const QVariant &var, void *data, const QByteArray &typeName, uint type) +{ + if (!data) + return true; + + if (type == QVariant::LastType || (type == 0 && typeName == "QVariant")) { + *(QVariant*)data = var; + return true; + } + + switch (var.type()) { + case QVariant::Invalid: + break; + case QVariant::String: + *(QString*)data = var.toString(); + break; + case QVariant::Int: + *(int*)data = var.toInt(); + break; + case QVariant::UInt: + *(uint*)data = var.toUInt(); + break; + case QVariant::Bool: + *(bool*)data = var.toBool(); + break; + case QVariant::Double: + *(double*)data = var.toDouble(); + break; + case QVariant::Color: + *(QColor*)data = qvariant_cast<QColor>(var); + break; + case QVariant::Date: + *(QDate*)data = var.toDate(); + break; + case QVariant::Time: + *(QTime*)data = var.toTime(); + break; + case QVariant::DateTime: + *(QDateTime*)data = var.toDateTime(); + break; + case QVariant::Font: + *(QFont*)data = qvariant_cast<QFont>(var); + break; + case QVariant::Pixmap: + *(QPixmap*)data = qvariant_cast<QPixmap>(var); + break; +#ifndef QT_NO_CURSOR + case QVariant::Cursor: + *(QCursor*)data = qvariant_cast<QCursor>(var); + break; +#endif + case QVariant::List: + *(QList<QVariant>*)data = var.toList(); + break; + case QVariant::StringList: + *(QStringList*)data = var.toStringList(); + break; + case QVariant::ByteArray: + *(QByteArray*)data = var.toByteArray(); + break; + case QVariant::LongLong: + *(qint64*)data = var.toLongLong(); + break; + case QVariant::ULongLong: + *(quint64*)data = var.toULongLong(); + break; + case QVariant::Rect: + *(QRect*)data = var.toRect(); + break; + case QVariant::Size: + *(QSize*)data = var.toSize(); + break; + case QVariant::Point: + *(QPoint*)data = var.toPoint(); + break; + case QVariant::UserType: + *(void**)data = *(void**)var.constData(); +// qVariantGet(var, *(void**)data, typeName); + break; + default: + qWarning("QVariantToVoidStar: Unhandled QVariant type"); + return false; + } + + return true; +} + +/*! + Returns \a arg as a QVariant of type \a type. + + Used by + + QAxServerBase: + - QAxServerBase::qt_metacall(update out parameters/return value) + - IDispatch::Invoke(METHOD, PROPERTYPUT) + - IPersistPropertyBag::Load + + QAxBase: + - IDispatch::Invoke (QAxEventSink) + - QAxBase::internalProperty(ReadProperty) + - QAxBase::internalInvoke(update out parameters/return value) + - QAxBase::dynamicCallHelper(update out parameters) + - QAxBase::dynamicCall(return value) + - IPropertyBag::Write (QtPropertyBag) +*/ +QVariant VARIANTToQVariant(const VARIANT &arg, const QByteArray &typeName, uint type) +{ + QVariant var; + switch(arg.vt) { + case VT_BSTR: + var = QString::fromWCharArray(arg.bstrVal); + break; + case VT_BSTR|VT_BYREF: + var = QString::fromWCharArray(*arg.pbstrVal); + break; + case VT_BOOL: + var = QVariant((bool)arg.boolVal); + break; + case VT_BOOL|VT_BYREF: + var = QVariant((bool)*arg.pboolVal); + break; + case VT_I1: + var = arg.cVal; + if (typeName == "char") + type = QVariant::Int; + break; + case VT_I1|VT_BYREF: + var = *arg.pcVal; + if (typeName == "char") + type = QVariant::Int; + break; + case VT_I2: + var = arg.iVal; + if (typeName == "short") + type = QVariant::Int; + break; + case VT_I2|VT_BYREF: + var = *arg.piVal; + if (typeName == "short") + type = QVariant::Int; + break; + case VT_I4: + if (type == QVariant::Color || (!type && typeName == "QColor")) + var = QVariant::fromValue(OLEColorToQColor(arg.lVal)); +#ifndef QT_NO_CURSOR + else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) + var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(arg.lVal))); +#endif + else + var = (int)arg.lVal; + break; + case VT_I4|VT_BYREF: + if (type == QVariant::Color || (!type && typeName == "QColor")) + var = QVariant::fromValue(OLEColorToQColor((int)*arg.plVal)); +#ifndef QT_NO_CURSOR + else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) + var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(*arg.plVal))); +#endif + else + var = (int)*arg.plVal; + break; + case VT_INT: + var = arg.intVal; + break; + case VT_INT|VT_BYREF: + var = *arg.pintVal; + break; + case VT_UI1: + var = arg.bVal; + break; + case VT_UI1|VT_BYREF: + var = *arg.pbVal; + break; + case VT_UI2: + var = arg.uiVal; + break; + case VT_UI2|VT_BYREF: + var = *arg.puiVal; + break; + case VT_UI4: + if (type == QVariant::Color || (!type && typeName == "QColor")) + var = QVariant::fromValue(OLEColorToQColor(arg.ulVal)); +#ifndef QT_NO_CURSOR + else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) + var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(arg.ulVal))); +#endif + else + var = (int)arg.ulVal; + break; + case VT_UI4|VT_BYREF: + if (type == QVariant::Color || (!type && typeName == "QColor")) + var = QVariant::fromValue(OLEColorToQColor((uint)*arg.pulVal)); +#ifndef QT_NO_CURSOR + else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) + var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(*arg.pulVal))); +#endif + else + var = (int)*arg.pulVal; + break; + case VT_UINT: + var = arg.uintVal; + break; + case VT_UINT|VT_BYREF: + var = *arg.puintVal; + break; + case VT_CY: + var = arg.cyVal.int64; + break; + case VT_CY|VT_BYREF: + var = arg.pcyVal->int64; + break; +#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400 + case VT_I8: + var = arg.llVal; + break; + case VT_I8|VT_BYREF: + var = *arg.pllVal; + break; + case VT_UI8: + var = arg.ullVal; + break; + case VT_UI8|VT_BYREF: + var = *arg.pullVal; + break; +#endif + case VT_R4: + var = arg.fltVal; + break; + case VT_R4|VT_BYREF: + var = *arg.pfltVal; + break; + case VT_R8: + var = arg.dblVal; + break; + case VT_R8|VT_BYREF: + var = *arg.pdblVal; + break; + case VT_DATE: + var = DATEToQDateTime(arg.date); + if (type == QVariant::Date || (!type && (typeName == "QDate" || typeName == "QDate*"))) { + var.convert(QVariant::Date); + } else if (type == QVariant::Time || (!type && (typeName == "QTime" || typeName == "QTime*"))) { + var.convert(QVariant::Time); + } + break; + case VT_DATE|VT_BYREF: + var = DATEToQDateTime(*arg.pdate); + if (type == QVariant::Date || (!type && (typeName == "QDate" || typeName == "QDate*"))) { + var.convert(QVariant::Date); + } else if (type == QVariant::Time || (!type && (typeName == "QTime" || typeName == "QTime*"))) { + var.convert(QVariant::Time); + } + break; + case VT_VARIANT: + case VT_VARIANT|VT_BYREF: + if (arg.pvarVal) + var = VARIANTToQVariant(*arg.pvarVal, typeName); + break; + + case VT_DISPATCH: + case VT_DISPATCH|VT_BYREF: + { + // pdispVal and ppdispVal are a union + IDispatch *disp = 0; + if (arg.vt & VT_BYREF) + disp = *arg.ppdispVal; + else + disp = arg.pdispVal; + if (type == QVariant::Font || (!type && (typeName == "QFont" || typeName == "QFont*"))) { + IFont *ifont = 0; + if (disp) + disp->QueryInterface(IID_IFont, (void**)&ifont); + if (ifont) { + var = QVariant::fromValue(IFontToQFont(ifont)); + ifont->Release(); + } else { + var = QVariant::fromValue(QFont()); + } + } else if (type == QVariant::Pixmap || (!type && (typeName == "QPixmap" || typeName == "QPixmap*"))) { + IPicture *ipic = 0; + if (disp) + disp->QueryInterface(IID_IPicture, (void**)&ipic); + if (ipic) { + var = QVariant::fromValue(IPictureToQPixmap(ipic)); + ipic->Release(); + } else { + var = QVariant::fromValue(QPixmap()); + } + } else { +#ifdef QAX_SERVER + IAxServerBase *iface = 0; + if (disp && typeName != "IDispatch*") + disp->QueryInterface(IID_IAxServerBase, (void**)&iface); + if (iface) { + QObject *qObj = iface->qObject(); + iface->Release(); + var = QVariant(qRegisterMetaType<QObject*>(qObj ? QByteArray(qObj->metaObject()->className()) + '*' : typeName), &qObj); + } else +#endif + { + if (!typeName.isEmpty()) { + if (arg.vt & VT_BYREF) { + var = QVariant(qRegisterMetaType<IDispatch**>("IDispatch**"), &arg.ppdispVal); + } else { +#ifndef QAX_SERVER + if (typeName == "QVariant") { + QAxObject *object = new QAxObject(disp); + var = QVariant::fromValue<QAxObject*>(object); + } else if (typeName != "IDispatch*" && QMetaType::type(typeName)) { + QByteArray typeNameStr = QByteArray(typeName); + int pIndex = typeName.lastIndexOf('*'); + if (pIndex != -1) + typeNameStr = typeName.left(pIndex); + int metaType = QMetaType::type(typeNameStr); + Q_ASSERT(metaType != 0); + QAxObject *object = (QAxObject*)qax_createObjectWrapper(metaType, disp); + var = QVariant(QMetaType::type(typeName), &object); + } else +#endif + var = QVariant(qRegisterMetaType<IDispatch*>(typeName), &disp); + } + } + } + } + } + break; + case VT_UNKNOWN: + case VT_UNKNOWN|VT_BYREF: + { + IUnknown *unkn = 0; + if (arg.vt & VT_BYREF) + unkn = *arg.ppunkVal; + else + unkn = arg.punkVal; + var.setValue(unkn); + } + break; + case VT_ARRAY|VT_VARIANT: + case VT_ARRAY|VT_VARIANT|VT_BYREF: + { + SAFEARRAY *array = 0; + if ( arg.vt & VT_BYREF ) + array = *arg.pparray; + else + array = arg.parray; + + UINT cDims = array ? SafeArrayGetDim(array) : 0; + switch(cDims) { + case 1: + { + QVariantList list; + + long lBound, uBound; + SafeArrayGetLBound( array, 1, &lBound ); + SafeArrayGetUBound( array, 1, &uBound ); + + for ( long i = lBound; i <= uBound; ++i ) { + VARIANT var; + VariantInit( &var ); + SafeArrayGetElement( array, &i, &var ); + + QVariant qvar = VARIANTToQVariant( var, 0 ); + clearVARIANT( &var ); + list << qvar; + } + + var = list; + } + break; + + case 2: + { + QVariantList listList; // a list of lists + long dimIndices[2]; + + long xlBound, xuBound, ylBound, yuBound; + SafeArrayGetLBound(array, 1, &xlBound); + SafeArrayGetUBound(array, 1, &xuBound); + SafeArrayGetLBound(array, 2, &ylBound); + SafeArrayGetUBound(array, 2, &yuBound); + + for (long x = xlBound; x <= xuBound; ++x) { + QVariantList list; + + dimIndices[0] = x; + for (long y = ylBound; y <= yuBound; ++y) { + VARIANT var; + VariantInit(&var); + dimIndices[1] = y; + SafeArrayGetElement(array, dimIndices, &var); + + QVariant qvar = VARIANTToQVariant(var, 0); + clearVARIANT(&var); + list << qvar; + } + + listList << QVariant(list); + } + var = listList; + } + break; + default: + var = QVariantList(); + break; + } + } + break; + + case VT_ARRAY|VT_BSTR: + case VT_ARRAY|VT_BSTR|VT_BYREF: + { + SAFEARRAY *array = 0; + if (arg.vt & VT_BYREF) + array = *arg.pparray; + else + array = arg.parray; + + QStringList strings; + if (!array || array->cDims != 1) { + var = strings; + break; + } + + long lBound, uBound; + SafeArrayGetLBound(array, 1, &lBound); + SafeArrayGetUBound(array, 1, &uBound); + + for (long i = lBound; i <= uBound; ++i) { + BSTR bstr; + SafeArrayGetElement(array, &i, &bstr); + strings << QString::fromWCharArray(bstr); + SysFreeString(bstr); + } + + var = strings; + } + break; + + case VT_ARRAY|VT_UI1: + case VT_ARRAY|VT_UI1|VT_BYREF: + { + SAFEARRAY *array = 0; + if (arg.vt & VT_BYREF) + array = *arg.pparray; + else + array = arg.parray; + + QByteArray bytes; + if (!array || array->cDims != 1) { + var = bytes; + break; + } + + long lBound, uBound; + SafeArrayGetLBound(array, 1, &lBound); + SafeArrayGetUBound(array, 1, &uBound); + + if (uBound != -1) { // non-empty array + bytes.resize(uBound - lBound + 1); + char *data = bytes.data(); + char *src; + SafeArrayAccessData(array, (void**)&src); + memcpy(data, src, bytes.size()); + SafeArrayUnaccessData(array); + } + + var = bytes; + } + break; + +#if defined(QAX_SERVER) + case VT_RECORD: + case VT_RECORD|VT_BYREF: + if (arg.pvRecord && arg.pRecInfo) { + IRecordInfo *recordInfo = arg.pRecInfo; + void *record = arg.pvRecord; + GUID guid; + recordInfo->GetGuid(&guid); + + if (guid == CLSID_QRect) { + QRect qrect; + recordInfo->RecordCopy(record, &qrect); + var = qrect; + } else if (guid == CLSID_QSize) { + QSize qsize; + recordInfo->RecordCopy(record, &qsize); + var = qsize; + } else if (guid == CLSID_QPoint) { + QPoint qpoint; + recordInfo->RecordCopy(record, &qpoint); + var = qpoint; + } + } + break; +#endif // QAX_SERVER + default: +#if !defined(Q_OS_WINCE) + // support for any SAFEARRAY(Type) where Type can be converted to a QVariant + // -> QVariantList + if (arg.vt & VT_ARRAY) { + SAFEARRAY *array = 0; + if (arg.vt & VT_BYREF) + array = *arg.pparray; + else + array = arg.parray; + + QVariantList list; + if (!array || array->cDims != 1) { + var = list; + break; + } + + // find out where to store the element + VARTYPE vt; + VARIANT variant; + SafeArrayGetVartype(array, &vt); + + void *pElement = 0; + switch(vt) { + case VT_BSTR: Q_ASSERT(false); break; // already covered + case VT_BOOL: pElement = &variant.boolVal; break; + case VT_I1: pElement = &variant.cVal; break; + case VT_I2: pElement = &variant.iVal; break; + case VT_I4: pElement = &variant.lVal; break; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + case VT_I8: pElement = &variant.llVal; break; + case VT_UI8: pElement = &variant.ullVal; break; +#endif + case VT_INT: pElement = &variant.intVal; break; + case VT_UI1: Q_ASSERT(false); break; // already covered + case VT_UI2: pElement = &variant.uiVal; break; + case VT_UI4: pElement = &variant.ulVal; break; + case VT_UINT: pElement = &variant.uintVal; break; + case VT_CY: pElement = &variant.cyVal; break; + case VT_R4: pElement = &variant.fltVal; break; + case VT_R8: pElement = &variant.dblVal; break; + case VT_DATE: pElement = &variant.date; break; + case VT_VARIANT: Q_ASSERT(false); break; // already covered + default: + break; + } + if (!pElement) { + var = list; + break; + } + + long lBound, uBound; + SafeArrayGetLBound( array, 1, &lBound ); + SafeArrayGetUBound( array, 1, &uBound ); + + for ( long i = lBound; i <= uBound; ++i ) { + variant.vt = vt; + SafeArrayGetElement(array, &i, pElement); + QVariant qvar = VARIANTToQVariant(variant, 0); + clearVARIANT(&variant); + list << qvar; + } + + var = list; + } +#endif + break; + } + + QVariant::Type proptype = (QVariant::Type)type; + if (proptype == QVariant::Invalid && !typeName.isEmpty()) { + if (typeName != "QVariant") + proptype = QVariant::nameToType(typeName); + } + if (proptype != QVariant::LastType && proptype != QVariant::Invalid && var.type() != proptype) { + if (var.canConvert(proptype)) { + QVariant oldvar = var; + if (oldvar.convert(proptype)) + var = oldvar; + } else if (proptype == QVariant::StringList && var.type() == QVariant::List) { + bool allStrings = true; + QStringList strings; + const QList<QVariant> list(var.toList()); + for (QList<QVariant>::ConstIterator it(list.begin()); it != list.end(); ++it) { + QVariant variant = *it; + if (variant.canConvert(QVariant::String)) + strings << variant.toString(); + else + allStrings = false; + } + if (allStrings) + var = strings; + } else { + var = QVariant(); + } + } + return var; +} + +void clearVARIANT(VARIANT *var) +{ + if (var->vt & VT_BYREF) { + switch(var->vt) { + case VT_BSTR|VT_BYREF: + SysFreeString(*var->pbstrVal); + delete var->pbstrVal; + break; + case VT_BOOL|VT_BYREF: + delete var->pboolVal; + break; + case VT_I1|VT_BYREF: + delete var->pcVal; + break; + case VT_I2|VT_BYREF: + delete var->piVal; + break; + case VT_I4|VT_BYREF: + delete var->plVal; + break; + case VT_INT|VT_BYREF: + delete var->pintVal; + break; + case VT_UI1|VT_BYREF: + delete var->pbVal; + break; + case VT_UI2|VT_BYREF: + delete var->puiVal; + break; + case VT_UI4|VT_BYREF: + delete var->pulVal; + break; + case VT_UINT|VT_BYREF: + delete var->puintVal; + break; +#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400 + case VT_I8|VT_BYREF: + delete var->pllVal; + break; + case VT_UI8|VT_BYREF: + delete var->pullVal; + break; +#endif + case VT_CY|VT_BYREF: + delete var->pcyVal; + break; + case VT_R4|VT_BYREF: + delete var->pfltVal; + break; + case VT_R8|VT_BYREF: + delete var->pdblVal; + break; + case VT_DATE|VT_BYREF: + delete var->pdate; + break; + case VT_DISPATCH|VT_BYREF: + (*var->ppdispVal)->Release(); + delete var->ppdispVal; + break; + case VT_ARRAY|VT_VARIANT|VT_BYREF: + case VT_ARRAY|VT_UI1|VT_BYREF: + case VT_ARRAY|VT_BSTR|VT_BYREF: + SafeArrayDestroy(*var->pparray); + delete var->pparray; + break; + case VT_VARIANT|VT_BYREF: + delete var->pvarVal; + break; + } + VariantInit(var); + } else { + VariantClear(var); + } +} + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT diff --git a/src/activeqt/shared/qaxtypes.h b/src/activeqt/shared/qaxtypes.h new file mode 100644 index 0000000..8f76390 --- /dev/null +++ b/src/activeqt/shared/qaxtypes.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAXTYPES_H +#define QAXTYPES_H + +#if !defined(_WINDOWS_) && !defined(_WINDOWS_H) && !defined(__WINDOWS__) +#error Must include windows.h first! +#endif + +#include <QtGui/qcolor.h> +#include <QtGui/qfont.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(ActiveQt) + +#ifndef QT_NO_WIN_ACTIVEQT + +extern GUID IID_IAxServerBase; +struct IAxServerBase : public IUnknown +{ + virtual IUnknown *clientSite() const = 0; + virtual void emitPropertyChanged(const char*) = 0; + virtual bool emitRequestPropertyChange(const char*) = 0; + virtual QObject *qObject() const = 0; + virtual void reportError(int code, const QString &src, const QString &desc, const QString &context) = 0; +}; + +#define HIMETRIC_PER_INCH 2540 +#define MAP_PIX_TO_LOGHIM(x,ppli) ((HIMETRIC_PER_INCH*(x) + ((ppli)>>1)) / (ppli)) +#define MAP_LOGHIM_TO_PIX(x,ppli) (((ppli)*(x) + HIMETRIC_PER_INCH/2) / HIMETRIC_PER_INCH) +#define QAX_NUM_PARAMS 8 + +static inline BSTR QStringToBSTR(const QString &str) +{ + return SysAllocStringLen((OLECHAR*)str.unicode(), str.length()); +} + +static inline uint QColorToOLEColor(const QColor &col) +{ + return qRgba(col.blue(), col.green(), col.red(), 0x00); +} + +extern QColor OLEColorToQColor(uint col); + +extern bool QVariantToVARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeName = 0, bool out = false); +extern QVariant VARIANTToQVariant(const VARIANT &arg, const QByteArray &typeName, uint type = 0); +extern bool QVariantToVoidStar(const QVariant &var, void *data, const QByteArray &typeName, uint type = 0); +extern void clearVARIANT(VARIANT *var); + +#define QAX_INPROC_SERVER (0x51540001) +#define QAX_OUTPROC_SERVER (0x51540002) + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT + +QT_END_HEADER + +#endif // QAXTYPES_H diff --git a/tools/dumpcpp/dumpcpp.pro b/tools/dumpcpp/dumpcpp.pro new file mode 100644 index 0000000..09a339b --- /dev/null +++ b/tools/dumpcpp/dumpcpp.pro @@ -0,0 +1,6 @@ +TEMPLATE = app + +CONFIG += console qaxcontainer +DESTDIR = ../../../bin + +SOURCES += main.cpp diff --git a/tools/dumpcpp/main.cpp b/tools/dumpcpp/main.cpp new file mode 100644 index 0000000..f95d31d --- /dev/null +++ b/tools/dumpcpp/main.cpp @@ -0,0 +1,1504 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QAxObject> +#include <QFile> +#include <QMetaObject> +#include <QMetaEnum> +#include <QTextStream> +#include <QSettings> +#include <QStringList> +#include <QUuid> +#include <QWidget> +#include <QFileInfo> +#include <qt_windows.h> +#include <ocidl.h> + +QT_BEGIN_NAMESPACE + +static ITypeInfo *currentTypeInfo = 0; + +enum ObjectCategory +{ + DefaultObject = 0x00, + SubObject = 0x001, + ActiveX = 0x002, + NoMetaObject = 0x004, + NoImplementation = 0x008, + NoDeclaration = 0x010, + NoInlines = 0x020, + OnlyInlines = 0x040, + DoNothing = 0x080, + Licensed = 0x100, + TypeLibID = 0x101 +}; + +// this comes from moc/qmetaobject.cpp +enum ProperyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resetable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, + Override = 0x00000200, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000 +}; + +enum MemberFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + MemberMethod = 0x00, + MemberSignal = 0x04, + MemberSlot = 0x08, + MemberCompatibility = 0x10, + MemberCloned = 0x20, + MemberScriptable = 0x40, +}; + +extern QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject); +extern QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject); +extern QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject); +extern QList<QByteArray> qax_qualified_usertypes; +extern QString qax_docuFromName(ITypeInfo *typeInfo, const QString &name); +extern bool qax_dispatchEqualsIDispatch; + +QByteArray nameSpace; +QMap<QByteArray, QByteArray> namespaceForType; + +void writeEnums(QTextStream &out, const QMetaObject *mo) +{ + // enums + for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) { + QMetaEnum metaEnum = mo->enumerator(ienum); + out << " enum " << metaEnum.name() << " {" << endl; + for (int k = 0; k < metaEnum.keyCount(); ++k) { + QByteArray key(metaEnum.key(k)); + out << " " << key.leftJustified(24) << "= " << metaEnum.value(k); + if (k < metaEnum.keyCount() - 1) + out << ","; + out << endl; + } + out << " };" << endl; + out << endl; + } +} + +void writeHeader(QTextStream &out, const QByteArray &nameSpace, const QString &outFileName) +{ + out << "#ifndef QAX_DUMPCPP_" << outFileName.toUpper() << "_H" << endl; + out << "#define QAX_DUMPCPP_" << outFileName.toUpper() << "_H" << endl; + out << endl; + out << "// Define this symbol to __declspec(dllexport) or __declspec(dllimport)" << endl; + out << "#ifndef " << nameSpace.toUpper() << "_EXPORT" << endl; + out << "#define " << nameSpace.toUpper() << "_EXPORT" << endl; + out << "#endif" << endl; + out << endl; + out << "#include <qaxobject.h>" << endl; + out << "#include <qaxwidget.h>" << endl; + out << "#include <qdatetime.h>" << endl; + out << "#include <qpixmap.h>" << endl; + out << endl; + out << "struct IDispatch;" << endl; + out << endl; +} + +void generateNameSpace(QTextStream &out, const QMetaObject *mo, const QByteArray &nameSpace) +{ + out << "namespace " << nameSpace << " {" << endl; + out << endl; + writeEnums(out, mo); + + // don't close on purpose +} + +static QByteArray joinParameterNames(const QList<QByteArray> ¶meterNames) +{ + QByteArray slotParameters; + for (int p = 0; p < parameterNames.count(); ++p) { + slotParameters += parameterNames.at(p); + if (p < parameterNames.count() - 1) + slotParameters += ','; + } + + return slotParameters; +} + +QByteArray constRefify(const QByteArray &type) +{ + QByteArray ctype(type); + if (type == "QString" || type == "QPixmap" + || type == "QVariant" || type == "QDateTime" + || type == "QColor" || type == "QFont" + || type == "QByteArray" || type == "QValueList<QVariant>" + || type == "QStringList") + ctype = "const " + ctype + "&"; + + return ctype; +} + +void generateClassDecl(QTextStream &out, const QString &controlID, const QMetaObject *mo, const QByteArray &className, const QByteArray &nameSpace, ObjectCategory category) +{ + QList<QByteArray> functions; + + QByteArray indent; + if (!(category & OnlyInlines)) + indent = " "; + + if (!(category & OnlyInlines)) { + // constructors + out << "class " << nameSpace.toUpper() << "_EXPORT " << className << " : public "; + if (category & ActiveX) + out << "QAxWidget"; + else + out << "QAxObject"; + out << endl; + + out << "{" << endl; + out << "public:" << endl; + out << " " << className << "("; + if (category & Licensed) + out << "const QString &licenseKey = QString(), "; + if (category & ActiveX) + out << "QWidget *parent = 0, Qt::WindowFlags f"; + else if (category & SubObject) + out << "IDispatch *subobject = 0, QAxObject *parent"; + else + out << "QObject *parent"; + out << " = 0)" << endl; + out << " : "; + if (category & ActiveX) + out << "QAxWidget(parent, f"; + else if (category & SubObject) + out << "QAxObject((IUnknown*)subobject, parent"; + else + out << "QAxObject(parent"; + out << ")" << endl; + out << " {" << endl; + if (category & SubObject) + out << " internalRelease();" << endl; + else if (category & Licensed) { + out << " if (licenseKey.isEmpty())" << endl; + out << " setControl(\"" << controlID << "\");" << endl; + out << " else" << endl; + out << " setControl(\"" << controlID << ":\" + licenseKey);" << endl; + } else { + out << " setControl(\"" << controlID << "\");" << endl; + } + out << " }" << endl; + out << endl; + + for (int ci = mo->classInfoOffset(); ci < mo->classInfoCount(); ++ci) { + QMetaClassInfo info = mo->classInfo(ci); + QByteArray iface_name = info.name(); + if (iface_name.startsWith("Event ")) + continue; + + QByteArray iface_class = info.value(); + + out << " " << className << "(" << iface_class << " *iface)" << endl; + + if (category & ActiveX) + out << " : QAxWidget()" << endl; + else + out << " : QAxObject()" << endl; + out << " {" << endl; + out << " initializeFrom(iface);" << endl; + out << " delete iface;" << endl; + out << " }" << endl; + out << endl; + } + } + + functions << className; + + // enums + if (nameSpace.isEmpty() && !(category & OnlyInlines)) { + for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) { + QMetaEnum metaEnum = mo->enumerator(ienum); + out << " enum " << metaEnum.name() << " {" << endl; + for (int k = 0; k < metaEnum.keyCount(); ++k) { + QByteArray key(metaEnum.key(k)); + out << " " << key.leftJustified(24) << "= " << metaEnum.value(k); + if (k < metaEnum.keyCount() - 1) + out << ","; + out << endl; + } + out << " };" << endl; + out << endl; + } + } + // QAxBase public virtual functions. + QList<QByteArray> axBase_vfuncs; + axBase_vfuncs.append("metaObject"); + axBase_vfuncs.append("qObject"); + axBase_vfuncs.append("className"); + axBase_vfuncs.append("propertyWritable"); + axBase_vfuncs.append("setPropertyWritable"); + + // properties + for (int iprop = mo->propertyOffset(); iprop < mo->propertyCount(); ++iprop) { + QMetaProperty property = mo->property(iprop); + if (!property.isReadable()) + continue; + + QByteArray propertyName(property.name()); + if (propertyName == "control" || propertyName == className) + continue; + + if (!(category & OnlyInlines)) { + out << indent << "/*" << endl << indent << "Property " << propertyName << endl; + QString documentation = qax_docuFromName(currentTypeInfo, QString::fromLatin1(propertyName.constData())); + if (!documentation.isEmpty()) { + out << endl; + out << indent << documentation << endl; + } + out << indent << "*/" << endl; + } + + // Check whether the new function conflicts with any of QAxBase public virtual functions. + // If so, prepend the function name with '<classname>_'. Since all internal metaobject magic + // remains the same, we have to use the original name when used with QObject::connect or QMetaObject + QByteArray propertyFunctionName(propertyName); + if (axBase_vfuncs.contains(propertyFunctionName)) { + propertyFunctionName = className + "_" + propertyName; + qWarning("property conflits with QAXBase: %s changed to %s", propertyName.constData(), propertyFunctionName.constData()); + } + + QByteArray propertyType(property.typeName()); + QByteArray castType(propertyType); + + QByteArray simplePropType = propertyType; + simplePropType.replace('*', ""); + + out << indent << "inline "; + bool foreignNamespace = true; + if (!propertyType.contains("::") && + (qax_qualified_usertypes.contains(simplePropType) || qax_qualified_usertypes.contains("enum "+ simplePropType)) + ) { + propertyType = nameSpace + "::" + propertyType; + foreignNamespace = false; + } + + out << propertyType << " "; + + if (category & OnlyInlines) + out << className << "::"; + out << propertyFunctionName << "() const"; + + if (!(category & NoInlines)) { + out << endl << indent << "{" << endl; + if (qax_qualified_usertypes.contains(simplePropType)) { + out << indent << " " << propertyType << " qax_pointer = 0;" << endl; + out << indent << " qRegisterMetaType(\"" << property.typeName() << "\", &qax_pointer);" << endl; + if (foreignNamespace) + out << "#ifdef QAX_DUMPCPP_" << propertyType.left(propertyType.indexOf("::")).toUpper() << "_H" << endl; + out << indent << " qRegisterMetaType(\"" << simplePropType << "\", qax_pointer);" << endl; + if (foreignNamespace) + out << "#endif" << endl; + } + out << indent << " QVariant qax_result = property(\"" << propertyName << "\");" << endl; + if (propertyType.length() && propertyType.at(propertyType.length()-1) == '*') + out << indent << " if (!qax_result.constData()) return 0;" << endl; + out << indent << " Q_ASSERT(qax_result.isValid());" << endl; + if (qax_qualified_usertypes.contains(simplePropType)) { + simplePropType = propertyType; + simplePropType.replace('*', ""); + if (foreignNamespace) + out << "#ifdef QAX_DUMPCPP_" << propertyType.left(propertyType.indexOf("::")).toUpper() << "_H" << endl; + out << indent << " return *(" << propertyType << "*)qax_result.constData();" << endl; + if (foreignNamespace) { + out << "#else" << endl; + out << indent << " return 0; // foreign namespace not included" << endl; + out << "#endif" << endl; + } + + } else { + out << indent << " return *(" << propertyType << "*)qax_result.constData();" << endl; + } + out << indent << "}" << endl; + } else { + out << "; //Returns the value of " << propertyName << endl; + } + + functions << propertyName; + + if (property.isWritable()) { + QByteArray setter(propertyName); + QChar firstChar = QLatin1Char(setter.at(0)); + if (isupper(setter.at(0))) { + setter = "Set" + setter; + } else { + setter[0] = toupper(setter[0]); + setter = "set" + setter; + } + + out << indent << "inline " << "void "; + if (category & OnlyInlines) + out << className << "::"; + out << setter << "(" << constRefify(propertyType) << " value)"; + + if (!(category & NoInlines)) { + if (propertyType.endsWith('*')) { + out << "{" << endl; + out << " int typeId = qRegisterMetaType(\"" << propertyType << "\", &value);" << endl; + out << " setProperty(\"" << propertyName << "\", QVariant(typeId, &value));" << endl; + out << "}" << endl; + } else { + out << "{ setProperty(\"" << propertyName << "\", QVariant(value)); }" << endl; + } + } else { + out << "; //Sets the value of the " << propertyName << " property" << endl; + } + + functions << setter; + } + + out << endl; + } + + // slots - but not property setters + int defaultArguments = 0; + for (int islot = mo->methodOffset(); islot < mo->methodCount(); ++islot) { + const QMetaMethod slot(mo->method(islot)); + if (slot.methodType() != QMetaMethod::Slot) + continue; + +#if 0 + // makes not sense really to respect default arguments... + if (slot.attributes() & Cloned) { + ++defaultArguments; + continue; + } +#endif + + QByteArray slotSignature(slot.signature()); + QByteArray slotName = slotSignature.left(slotSignature.indexOf('(')); + if (functions.contains(slotName)) + continue; + + if (!(category & OnlyInlines)) { + out << indent << "/*" << endl << indent << "Method " << slotName << endl; + QString documentation = qax_docuFromName(currentTypeInfo, QString::fromLatin1(slotName.constData())); + if (!documentation.isEmpty()) { + out << endl; + out << indent << documentation << endl; + } + out << indent << "*/" << endl; + } + + QByteArray slotParameters(joinParameterNames(slot.parameterNames())); + QByteArray slotTag(slot.tag()); + QByteArray slotType(slot.typeName()); + + QByteArray simpleSlotType = slotType; + simpleSlotType.replace('*', ""); + if (!slotType.contains("::") && qax_qualified_usertypes.contains(simpleSlotType)) + slotType = nameSpace + "::" + slotType; + + + QByteArray slotNamedSignature; + if (slotSignature.endsWith("()")) { // no parameters - no names + slotNamedSignature = slotSignature; + } else { + slotNamedSignature = slotSignature.left(slotSignature.indexOf('(') + 1); + QByteArray slotSignatureTruncated(slotSignature.mid(slotNamedSignature.length())); + slotSignatureTruncated.truncate(slotSignatureTruncated.length() - 1); + + QList<QByteArray> signatureSplit = slotSignatureTruncated.split(','); + QList<QByteArray> parameterSplit; + if (slotParameters.isEmpty()) { // generate parameter names + for (int i = 0; i < signatureSplit.count(); ++i) + parameterSplit << QByteArray("p") + QByteArray::number(i); + } else { + parameterSplit = slotParameters.split(','); + } + + for (int i = 0; i < signatureSplit.count(); ++i) { + QByteArray parameterType = signatureSplit.at(i); + if (!parameterType.contains("::") && namespaceForType.contains(parameterType)) + parameterType = namespaceForType.value(parameterType) + "::" + parameterType; + + slotNamedSignature += constRefify(parameterType); + slotNamedSignature += " "; + slotNamedSignature += parameterSplit.at(i); + if (defaultArguments >= signatureSplit.count() - i) { + slotNamedSignature += " = "; + slotNamedSignature += parameterType + "()"; + } + if (i + 1 < signatureSplit.count()) + slotNamedSignature += ", "; + } + slotNamedSignature += ')'; + } + + out << indent << "inline "; + + if (!slotTag.isEmpty()) + out << slotTag << " "; + if (slotType.isEmpty()) + out << "void "; + else + out << slotType << " "; + if (category & OnlyInlines) + out << className << "::"; + + // Update function name in case of conflicts with QAxBase public virtual functions. + int parnIdx = slotNamedSignature.indexOf('('); + QByteArray slotOriginalName = slotNamedSignature.left(parnIdx); + if (axBase_vfuncs.contains(slotOriginalName)) { + QByteArray newSignature = className + "_" + slotOriginalName; + newSignature += slotNamedSignature.mid(parnIdx); + qWarning("function name conflits with QAXBase %s changed to %s", slotNamedSignature.constData(), newSignature.constData()); + slotNamedSignature = newSignature; + } + + out << slotNamedSignature; + + if (category & NoInlines) { + out << ";" << endl; + } else { + out << endl; + out << indent << "{" << endl; + + if (!slotType.isEmpty()) { + out << indent << " " << slotType << " qax_result"; + if (slotType.endsWith('*')) + out << " = 0"; + out << ";" << endl; + if (qax_qualified_usertypes.contains(simpleSlotType)) { + out << indent << " qRegisterMetaType(\"" << simpleSlotType << "*\", &qax_result);" << endl; + bool foreignNamespace = simpleSlotType.contains("::"); + if (foreignNamespace) + out << "#ifdef QAX_DUMPCPP_" << simpleSlotType.left(simpleSlotType.indexOf(':')).toUpper() << "_H" << endl; + out << indent << " qRegisterMetaType(\"" << simpleSlotType << "\", qax_result);" << endl; + if (foreignNamespace) + out << "#endif" << endl; + } + } + out << indent << " void *_a[] = {"; + if (!slotType.isEmpty()) + out << "(void*)&qax_result"; + else + out << "0"; + if (!slotParameters.isEmpty()) { + out << ", (void*)&"; + out << slotParameters.replace(",", ", (void*)&"); + } + out << "};" << endl; + + out << indent << " qt_metacall(QMetaObject::InvokeMetaMethod, " << islot << ", _a);" << endl; + if (!slotType.isEmpty()) + out << indent << " return qax_result;" << endl; + out << indent << "}" << endl; + } + + out << endl; + defaultArguments = 0; + } + + if (!(category & OnlyInlines)) { + if (!(category & NoMetaObject)) { + out << "// meta object functions" << endl; + out << " static const QMetaObject staticMetaObject;" << endl; + out << " virtual const QMetaObject *metaObject() const { return &staticMetaObject; }" << endl; + out << " virtual void *qt_metacast(const char *);" << endl; + } + + out << "};" << endl; + } +} + +#define addString(string, stringData) \ + out << stringDataLength << ", "; \ + stringData += string; \ + stringDataLength += qstrlen(string); \ + stringData += "\\0"; \ + lineLength += qstrlen(string) + 1; \ + if (lineLength > 200) { stringData += "\"\n \""; lineLength = 0; } \ + ++stringDataLength; + +void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray &className, const QByteArray &nameSpace, ObjectCategory category) +{ + QByteArray qualifiedClassName; + if (!nameSpace.isEmpty()) + qualifiedClassName = nameSpace + "::"; + qualifiedClassName += className; + + QByteArray stringData(qualifiedClassName); + int stringDataLength = stringData.length(); + stringData += "\\0\"\n"; + ++stringDataLength; + int lineLength = 0; + + int classInfoCount = mo->classInfoCount() - mo->classInfoOffset(); + int enumCount = mo->enumeratorCount() - mo->enumeratorOffset(); + int methodCount = mo->methodCount() - mo->methodOffset(); + int propertyCount = mo->propertyCount() - mo->propertyOffset(); + int enumStart = 10; + + out << "static const uint qt_meta_data_" << qualifiedClassName.replace(':', '_') << "[] = {" << endl; + out << endl; + out << " // content:" << endl; + out << " 1, // revision" << endl; + out << " 0, // classname" << endl; + out << " " << classInfoCount << ", " << (classInfoCount ? enumStart : 0) << ", // classinfo" << endl; + enumStart += classInfoCount * 2; + out << " " << methodCount << ", " << (methodCount ? enumStart : 0) << ", // methods" << endl; + enumStart += methodCount * 5; + out << " " << propertyCount << ", " << (propertyCount ? enumStart : 0) << ", // properties" << endl; + enumStart += propertyCount * 3; + out << " " << enumCount << ", " << (enumCount ? enumStart : 0) + << ", // enums/sets" << endl; + out << endl; + + if (classInfoCount) { + out << " // classinfo: key, value" << endl; + stringData += " \""; + for (int i = 0; i < classInfoCount; ++i) { + QMetaClassInfo classInfo = mo->classInfo(i + mo->classInfoOffset()); + out << " "; + addString(classInfo.name(), stringData); + addString(classInfo.value(), stringData); + out << endl; + } + stringData += "\"\n"; + out << endl; + } + if (methodCount) { + out << " // signals: signature, parameters, type, tag, flags" << endl; + stringData += " \""; + for (int i = 0; i < methodCount; ++i) { + const QMetaMethod signal(mo->method(i + mo->methodOffset())); + if (signal.methodType() != QMetaMethod::Signal) + continue; + out << " "; + addString(signal.signature(), stringData); + addString(joinParameterNames(signal.parameterNames()), stringData); + addString(signal.typeName(), stringData); + addString(signal.tag(), stringData); + out << (AccessProtected | signal.attributes() | MemberSignal) << "," << endl; + } + stringData += "\"\n"; + out << endl; + + out << " // slots: signature, parameters, type, tag, flags" << endl; + stringData += " \""; + for (int i = 0; i < methodCount; ++i) { + const QMetaMethod slot(mo->method(i + mo->methodOffset())); + if (slot.methodType() != QMetaMethod::Slot) + continue; + out << " "; + addString(slot.signature(), stringData); + addString(joinParameterNames(slot.parameterNames()), stringData); + addString(slot.typeName(), stringData); + addString(slot.tag(), stringData); + out << (0x01 | slot.attributes() | MemberSlot) << "," << endl; + } + stringData += "\"\n"; + out << endl; + } + if (propertyCount) { + out << " // properties: name, type, flags" << endl; + stringData += " \""; + for (int i = 0; i < propertyCount; ++i) { + QMetaProperty property = mo->property(i + mo->propertyOffset()); + out << " "; + addString(property.name(), stringData); + addString(property.typeName(), stringData); + + uint flags = 0; + uint vartype = property.type(); + if (vartype != QVariant::Invalid && vartype != QVariant::UserType) + flags = vartype << 24; + else if (QByteArray(property.typeName()) == "QVariant") + flags |= 0xff << 24; + + if (property.isReadable()) + flags |= Readable; + if (property.isWritable()) + flags |= Writable; + if (property.isEnumType()) + flags |= EnumOrFlag; + if (property.isDesignable()) + flags |= Designable; + if (property.isScriptable()) + flags |= Scriptable; + if (property.isStored()) + flags |= Stored; + if (property.isEditable()) + flags |= Editable; + + out << "0x" << QString::number(flags, 16).rightJustified(8, '0') << ", \t\t // " << property.typeName() << " " << property.name(); + out << endl; + } + stringData += "\"\n"; + out << endl; + } + + QByteArray enumStringData; + if (enumCount) { + out << " // enums: name, flags, count, data" << endl; + enumStringData += " \""; + enumStart += enumCount * 4; + for (int i = 0; i < enumCount; ++i) { + QMetaEnum enumerator = mo->enumerator(i + mo->enumeratorOffset()); + out << " "; + addString(enumerator.name(), enumStringData); + out << (enumerator.isFlag() ? "0x1" : "0x0") << ", " << enumerator.keyCount() << ", " << enumStart << ", " << endl; + enumStart += enumerator.keyCount() * 2; + } + enumStringData += "\"\n"; + out << endl; + + out << " // enum data: key, value" << endl; + for (int i = 0; i < enumCount; ++i) { + enumStringData += " \""; + QMetaEnum enumerator = mo->enumerator(i + mo->enumeratorOffset()); + for (int j = 0; j < enumerator.keyCount(); ++j) { + out << " "; + addString(enumerator.key(j), enumStringData); + if (nameSpace.isEmpty()) + out << className << "::"; + else + out << nameSpace << "::"; + out << enumerator.key(j) << "," << endl; + } + enumStringData += "\"\n"; + } + out << endl; + } + out << " 0 // eod" << endl; + out << "};" << endl; + out << endl; + + QByteArray stringGenerator; + + if (!nameSpace.isEmpty()) { + static bool firstStringData = true; + if (firstStringData) { // print enums only once + firstStringData = false; + if (!enumStringData.isEmpty()) { + // Maximum string length supported is 64K + int maxStringLength = 65535; + if (enumStringData.size() < maxStringLength) { + out << "static const char qt_meta_enumstringdata_" << nameSpace << "[] = {" << endl; + out << enumStringData << endl; + out << "};" << endl; + out << endl; + } else { + // split the string into fragments of 64k + int fragments = (enumStringData.size() / maxStringLength); + fragments += (enumStringData.size() % maxStringLength) ? 1 : 0; + int i, index; + // define the fragments (qt_meta_enumstringdata_<nameSpace>fragment#) + for (i = 0 , index = 0; i < fragments; i++, index += maxStringLength) { + out << "static const char qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) << "[] = {" << endl; + QByteArray fragment = enumStringData.mid(index, maxStringLength); + if (!(fragment[0] == ' ' || fragment[0] == '\n' || fragment[0] == '\"')) + out << "\""; + out << fragment; + int endIx = fragment.size() - 1; + if (!(fragment[endIx] == ' ' || fragment[endIx] == '\n' || fragment[endIx] == '\"' || fragment[endIx] == '\0')) + out << "\"" << endl; + else + out << endl; + out << "};" << endl; + } + // original array definition, size will be the combined size of the arrays defined above + out << "static char qt_meta_enumstringdata_" << nameSpace << "[" << endl; + for (i = 0; i < fragments; i++, index += maxStringLength) { + out << " "; + if (i) + out << "+ "; + out << "sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<")" << endl; + } + out << "] = {0};" << endl << endl; + // this class will initializes the original array in constructor + out << "class qt_meta_enumstringdata_" << nameSpace << "_init " << endl <<"{" <<endl; + out << "public:"<<endl; + out << " qt_meta_enumstringdata_" << nameSpace << "_init() " << endl <<" {" <<endl; + out << " int index = 0;" << endl; + for (i = 0; i < fragments; i++, index += maxStringLength) { + out << " memcpy(qt_meta_enumstringdata_" << nameSpace << " + index, " <<"qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i); + out << ", sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<") - 1);" << endl; + out << " index += sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<") - 1;" << endl; + } + out << " }" << endl << "};" << endl; + // a global variable of the class + out << "static qt_meta_enumstringdata_" << nameSpace << "_init qt_meta_enumstringdata_" << nameSpace << "_init_instance;" << endl << endl; + } + } + } + stringGenerator = "qt_meta_stringdata_" + qualifiedClassName.replace(':','_') + "()"; + out << "static const char *" << stringGenerator << " {" << endl; + QList<QByteArray> splitStrings; + + // workaround for compilers that can't handle string literals longer than 64k + int splitCount = 0; + do { + int lastNewline = stringData.lastIndexOf('\n', 64000); + QByteArray splitString = stringData.left(lastNewline); + + splitStrings << splitString; + out << " static const char stringdata" << splitCount << "[] = {" << endl; + out << " \"" << splitString << endl; + out << " };" << endl; + stringData = stringData.mid(lastNewline + 1); + if (stringData.startsWith(" \"")) + stringData = stringData.mid(5); + ++splitCount; + } while (!stringData.isEmpty()); + + out << " static char data["; + for (int i = 0; i < splitCount; ++i) { + out << "sizeof(stringdata" << i << ") + "; + } + if (!enumStringData.isEmpty()) { + out << "sizeof(qt_meta_enumstringdata_" << nameSpace << ")"; + } else { + out << "0"; + } + out << "];" << endl; + out << " if (!data[0]) {" << endl; + out << " int index = 0;" << endl; + + int dataIndex = 0; + for (int i = 0; i < splitCount; ++i) { + out << " memcpy(data + index"; + out << ", stringdata" << i << ", sizeof(stringdata" << i << ") - 1);" << endl; + out << " index += sizeof(stringdata" << i << ") - 1;" << endl; + dataIndex += splitStrings.at(i).length(); + } + if (!enumStringData.isEmpty()) { + out << " memcpy(data + index, qt_meta_enumstringdata_" << nameSpace << ", sizeof(qt_meta_enumstringdata_" << nameSpace << "));" << endl; + } + out << " }" << endl; + out << endl; + out << " return data;" << endl; + out << "};" << endl; + out << endl; + } else { + stringData += enumStringData; + stringGenerator = "qt_meta_stringdata_" + qualifiedClassName.replace(':','_'); + out << "static const char qt_meta_stringdata_" << stringGenerator << "[] = {" << endl; + out << " \"" << stringData << endl; + out << "};" << endl; + out << endl; + } + + out << "const QMetaObject " << className << "::staticMetaObject = {" << endl; + if (category & ActiveX) + out << "{ &QWidget::staticMetaObject," << endl; + else + out << "{ &QObject::staticMetaObject," << endl; + out << stringGenerator << "," << endl; + out << "qt_meta_data_" << qualifiedClassName.replace(':','_') << " }" << endl; + out << "};" << endl; + out << endl; + + out << "void *" << className << "::qt_metacast(const char *_clname)" << endl; + out << "{" << endl; + out << " if (!_clname) return 0;" << endl; + out << " if (!strcmp(_clname, " << stringGenerator << "))" << endl; + out << " return static_cast<void*>(const_cast<" << className << "*>(this));" << endl; + if (category & ActiveX) + out << " return QAxWidget::qt_metacast(_clname);" << endl; + else + out << " return QAxObject::qt_metacast(_clname);" << endl; + out << "}" << endl; +} + +bool generateClass(QAxObject *object, const QByteArray &className, const QByteArray &nameSpace, const QByteArray &outname, ObjectCategory category) +{ + IOleControl *control = 0; + object->queryInterface(IID_IOleControl, (void**)&control); + if (control) { + category = ActiveX; + control->Release(); + } + + const QMetaObject *mo = object->metaObject(); + + if (!nameSpace.isEmpty() && !(category & NoDeclaration)) { + QFile outfile(QString::fromLatin1(nameSpace.toLower().constData()) + QLatin1String(".h")); + if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("dumpcpp: Could not open output file '%s'", qPrintable(outfile.fileName())); + return false; + } + QTextStream out(&outfile); + + out << "/****************************************************************************" << endl; + out << "**" << endl; + out << "** Namespace " << nameSpace << " generated by dumpcpp" << endl; + out << "**" << endl; + out << "****************************************************************************/" << endl; + out << endl; + + writeHeader(out, nameSpace, outfile.fileName()); + generateNameSpace(out, mo, nameSpace); + + // close namespace file + out << "};" << endl; + out << endl; + + out << "#endif" << endl; + out << endl; + } + + if (!(category & NoDeclaration)) { + QFile outfile(QString::fromLatin1(outname.constData()) + QLatin1String(".h")); + if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("dumpcpp: Could not open output file '%s'", qPrintable(outfile.fileName())); + return false; + } + QTextStream out(&outfile); + + out << "/****************************************************************************" << endl; + out << "**" << endl; + out << "** Class declaration generated by dumpcpp" << endl; + out << "**" << endl; + out << "****************************************************************************/" << endl; + out << endl; + + out << "#include <qdatetime.h>" << endl; + if (category & ActiveX) + out << "#include <qaxwidget.h>" << endl; + else + out << "#include <qaxobject.h>" << endl; + out << endl; + + out << "struct IDispatch;" << endl, + out << endl; + + if (!nameSpace.isEmpty()) { + out << "#include \"" << nameSpace.toLower() << ".h\"" << endl; + out << endl; + out << "namespace " << nameSpace << " {" << endl; + } + + generateClassDecl(out, object->control(), mo, className, nameSpace, category); + + if (!nameSpace.isEmpty()) { + out << endl; + out << "};" << endl; + } + } + + if (!(category & (NoMetaObject|NoImplementation))) { + QFile outfile(QString::fromLatin1(outname.constData()) + QLatin1String(".cpp")); + if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("dumpcpp: Could not open output file '%s'", qPrintable(outfile.fileName())); + return false; + } + QTextStream out(&outfile); + + out << "#include <qmetaobject.h>" << endl; + out << "#include \"" << outname << ".h\"" << endl; + out << endl; + + if (!nameSpace.isEmpty()) { + out << "using namespace " << nameSpace << ";" << endl; + out << endl; + } + + generateClassImpl(out, mo, className, nameSpace, category); + } + + return true; +} + +bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, ObjectCategory category) +{ + QString typeLibFile(QString::fromLatin1(typeLib.constData())); + typeLibFile = typeLibFile.replace(QLatin1Char('/'), QLatin1Char('\\')); + QString cppFile(QString::fromLatin1(outname.constData())); + + ITypeLib *typelib; + LoadTypeLibEx(reinterpret_cast<const wchar_t *>(typeLibFile.utf16()), REGKIND_NONE, &typelib); + if (!typelib) { + qWarning("dumpcpp: loading '%s' as a type library failed", qPrintable(typeLibFile)); + return false; + } + + QString libName; + BSTR nameString; + typelib->GetDocumentation(-1, &nameString, 0, 0, 0); + libName = QString::fromWCharArray(nameString); + SysFreeString(nameString); + if (!nameSpace.isEmpty()) + libName = QString(nameSpace); + + QString libVersion(QLatin1String("1.0")); + + TLIBATTR *tlibattr = 0; + typelib->GetLibAttr(&tlibattr); + if (tlibattr) { + libVersion = QString::fromLatin1("%1.%2").arg(tlibattr->wMajorVerNum).arg(tlibattr->wMinorVerNum); + typelib->ReleaseTLibAttr(tlibattr); + } + + if (cppFile.isEmpty()) + cppFile = libName.toLower(); + + if (cppFile.isEmpty()) { + qWarning("dumpcpp: no output filename provided, and cannot deduce output filename"); + return false; + } + + QMetaObject *namespaceObject = qax_readEnumInfo(typelib, 0); + + QFile implFile(cppFile + QLatin1String(".cpp")); + QTextStream implOut(&implFile); + if (!(category & (NoMetaObject|NoImplementation))) { + if (!implFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("dumpcpp: Could not open output file '%s'", qPrintable(implFile.fileName())); + return false; + } + + implOut << "/****************************************************************************" << endl; + implOut << "**" << endl; + implOut << "** Metadata for " << libName << " generated by dumpcpp from type library" << endl; + implOut << "** " << typeLibFile << endl; + implOut << "**" << endl; + implOut << "****************************************************************************/" << endl; + implOut << endl; + + implOut << "#define QAX_DUMPCPP_" << libName.toUpper() << "_NOINLINES" << endl; + + implOut << "#include \"" << cppFile << ".h\"" << endl; + implOut << endl; + implOut << "using namespace " << libName << ";" << endl; + implOut << endl; + } + + QFile declFile(cppFile + QLatin1String(".h")); + QTextStream declOut(&declFile); + QByteArray classes; + QTextStream classesOut(&classes, QIODevice::WriteOnly); + QByteArray inlines; + QTextStream inlinesOut(&inlines, QIODevice::WriteOnly); + + QMap<QByteArray, QList<QByteArray> > namespaces; + + if(!(category & NoDeclaration)) { + if (!declFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("dumpcpp: Could not open output file '%s'", qPrintable(declFile.fileName())); + return false; + } + + declOut << "/****************************************************************************" << endl; + declOut << "**" << endl; + declOut << "** Namespace " << libName << " generated by dumpcpp from type library" << endl; + declOut << "** " << typeLibFile << endl; + declOut << "**" << endl; + declOut << "****************************************************************************/" << endl; + declOut << endl; + + QFileInfo cppFileInfo(cppFile); + writeHeader(declOut, libName.toLatin1(), cppFileInfo.fileName()); + + UINT typeCount = typelib->GetTypeInfoCount(); + if (declFile.isOpen()) { + declOut << endl; + declOut << "// Referenced namespace" << endl; + for (UINT index = 0; index < typeCount; ++index) { + ITypeInfo *typeinfo = 0; + typelib->GetTypeInfo(index, &typeinfo); + if (!typeinfo) + continue; + + TYPEATTR *typeattr; + typeinfo->GetTypeAttr(&typeattr); + if (!typeattr) { + typeinfo->Release(); + continue; + } + + TYPEKIND typekind; + typelib->GetTypeInfoType(index, &typekind); + + QMetaObject *metaObject = 0; + + // trigger meta object to collect references to other type libraries + switch (typekind) { + case TKIND_COCLASS: + if (category & ActiveX) + metaObject = qax_readClassInfo(typelib, typeinfo, &QWidget::staticMetaObject); + else + metaObject = qax_readClassInfo(typelib, typeinfo, &QObject::staticMetaObject); + break; + case TKIND_DISPATCH: + if (category & ActiveX) + metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QWidget::staticMetaObject); + else + metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QObject::staticMetaObject); + break; + case TKIND_RECORD: + case TKIND_ENUM: + case TKIND_INTERFACE: // only for forward declarations + { + QByteArray className; + BSTR bstr; + if (S_OK != typeinfo->GetDocumentation(-1, &bstr, 0, 0, 0)) + break; + className = QString::fromWCharArray(bstr).toLatin1(); + SysFreeString(bstr); + switch (typekind) { + case TKIND_RECORD: + className = "struct " + className; + break; + case TKIND_ENUM: + className = "enum " + className; + break; + default: + break; + } + namespaces[libName.toLatin1()].append(className); + if (!qax_qualified_usertypes.contains(className)) + qax_qualified_usertypes << className; + } + break; + default: + break; + } + + delete metaObject; + typeinfo->ReleaseTypeAttr(typeattr); + typeinfo->Release(); + } + + for (int i = 0; i < qax_qualified_usertypes.count(); ++i) { + QByteArray refType = qax_qualified_usertypes.at(i); + QByteArray refTypeLib; + if (refType.contains("::")) { + refTypeLib = refType; + refType = refType.mid(refType.lastIndexOf("::") + 2); + if (refTypeLib.contains(' ')) { + refType = refTypeLib.left(refTypeLib.indexOf(' ')) + ' ' + refType; + } + refTypeLib = refTypeLib.left(refTypeLib.indexOf("::")); + refTypeLib = refTypeLib.mid(refTypeLib.lastIndexOf(' ') + 1); + namespaces[refTypeLib].append(refType); + } else { + namespaces[libName.toLatin1()].append(refType); + } + } + + QList<QByteArray> keys = namespaces.keys(); + for (int n = 0; n < keys.count(); ++n) { + QByteArray nspace = keys.at(n); + if (QString::fromLatin1(nspace.constData()) != libName) { + declOut << "namespace " << nspace << " {" << endl; + QList<QByteArray> classList = namespaces.value(nspace); + for (int c = 0; c < classList.count(); ++c) { + QByteArray className = classList.at(c); + if (className.contains(' ')) { + declOut << " " << className << ";" << endl; + namespaceForType.insert(className.mid(className.indexOf(' ') + 1), nspace); + } else { + declOut << " class " << className << ";" << endl; + namespaceForType.insert(className, nspace); + namespaceForType.insert(className + "*", nspace); + } + } + declOut << "}" << endl << endl; + } + } + + declOut << endl; + } + generateNameSpace(declOut, namespaceObject, libName.toLatin1()); + + QList<QByteArray> classList = namespaces.value(libName.toLatin1()); + if (classList.count()) + declOut << "// forward declarations" << endl; + for (int c = 0; c < classList.count(); ++c) { + QByteArray className = classList.at(c); + if (className.contains(' ')) { + declOut << " " << className << ";" << endl; + namespaceForType.insert(className.mid(className.indexOf(' ') + 1), libName.toLatin1()); + } else { + declOut << " class " << className << ";" << endl; + namespaceForType.insert(className, libName.toLatin1()); + namespaceForType.insert(className + "*", libName.toLatin1()); + } + } + + declOut << endl; + } + + QList<QByteArray> subtypes; + + UINT typeCount = typelib->GetTypeInfoCount(); + for (UINT index = 0; index < typeCount; ++index) { + ITypeInfo *typeinfo = 0; + typelib->GetTypeInfo(index, &typeinfo); + if (!typeinfo) + continue; + + TYPEATTR *typeattr; + typeinfo->GetTypeAttr(&typeattr); + if (!typeattr) { + typeinfo->Release(); + continue; + } + + TYPEKIND typekind; + typelib->GetTypeInfoType(index, &typekind); + + uint object_category = category; + if (!(typeattr->wTypeFlags & TYPEFLAG_FCANCREATE)) + object_category |= SubObject; + else if (typeattr->wTypeFlags & TYPEFLAG_FCONTROL) + object_category |= ActiveX; + + QMetaObject *metaObject = 0; + QUuid guid(typeattr->guid); + + if (!(object_category & ActiveX)) { + QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID\\") + guid.toString(), QSettings::NativeFormat); + if (settings.childGroups().contains(QLatin1String("Control"))) { + object_category |= ActiveX; + object_category &= ~SubObject; + } + } + + switch (typekind) { + case TKIND_COCLASS: + if (object_category & ActiveX) + metaObject = qax_readClassInfo(typelib, typeinfo, &QWidget::staticMetaObject); + else + metaObject = qax_readClassInfo(typelib, typeinfo, &QObject::staticMetaObject); + break; + case TKIND_DISPATCH: + if (object_category & ActiveX) + metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QWidget::staticMetaObject); + else + metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QObject::staticMetaObject); + break; + case TKIND_INTERFACE: // only stub + { + QByteArray className; + BSTR bstr; + if (S_OK != typeinfo->GetDocumentation(-1, &bstr, 0, 0, 0)) + break; + className = QString::fromWCharArray(bstr).toLatin1(); + SysFreeString(bstr); + + declOut << "// stub for vtable-only interface" << endl; + declOut << "class " << className << " : public QAxObject {};" << endl << endl; + } + break; + default: + break; + } + + if (metaObject) { + currentTypeInfo = typeinfo; + QByteArray className(metaObject->className()); + if (!(typeattr->wTypeFlags & TYPEFLAG_FDUAL) + && (metaObject->propertyCount() - metaObject->propertyOffset()) == 1 + && className.contains("Events")) { + declOut << "// skipping event interface " << className << endl << endl; + } else { + if (declFile.isOpen()) { + if (typeattr->wTypeFlags & TYPEFLAG_FLICENSED) + object_category |= Licensed; + if (typekind == TKIND_COCLASS) { // write those later... + generateClassDecl(classesOut, guid.toString(), metaObject, className, libName.toLatin1(), (ObjectCategory)(object_category|NoInlines)); + classesOut << endl; + } else { + generateClassDecl(declOut, guid.toString(), metaObject, className, libName.toLatin1(), (ObjectCategory)(object_category|NoInlines)); + declOut << endl; + } + subtypes << className; + generateClassDecl(inlinesOut, guid.toString(), metaObject, className, libName.toLatin1(), (ObjectCategory)(object_category|OnlyInlines)); + inlinesOut << endl; + } + if (implFile.isOpen()) { + generateClassImpl(implOut, metaObject, className, libName.toLatin1(), (ObjectCategory)object_category); + implOut << endl; + } + } + currentTypeInfo = 0; + } + + delete metaObject; + + typeinfo->ReleaseTypeAttr(typeattr); + typeinfo->Release(); + } + + delete namespaceObject; + + classesOut.flush(); + inlinesOut.flush(); + + if (declFile.isOpen()) { + if (classes.size()) { + declOut << "// Actual coclasses" << endl; + declOut << classes; + } + if (inlines.size()) { + declOut << "// member function implementation" << endl; + declOut << "#ifndef QAX_DUMPCPP_" << libName.toUpper() << "_NOINLINES" << endl; + declOut << inlines << endl; + declOut << "#endif" << endl << endl; + } + // close namespace + declOut << "}" << endl; + declOut << endl; + + // partial template specialization for qMetaTypeConstructHelper + for (int t = 0; t < subtypes.count(); ++t) { + QByteArray subType(subtypes.at(t)); + declOut << "template<>" << endl; + declOut << "inline void *qMetaTypeConstructHelper(const " << libName << "::" << subType << " *t)" << endl; + declOut << "{ Q_ASSERT(!t); return new " << libName << "::" << subType << "; }" << endl; + declOut << endl; + } + + declOut << "#endif" << endl; + declOut << endl; + } + + typelib->Release(); + return true; +} + +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +int main(int argc, char **argv) +{ + qax_dispatchEqualsIDispatch = false; + + CoInitialize(0); + + uint category = DefaultObject; + + enum State { + Default = 0, + Output, + NameSpace, + GetTypeLib + } state; + state = Default; + + QByteArray outname; + QByteArray typeLib; + + for (int a = 1; a < argc; ++a) { + QByteArray arg(argv[a]); + const char first = arg[0]; + switch(state) { + case Default: + if (first == '-' || first == '/') { + arg = arg.mid(1); + arg.toLower(); + + if (arg == "o") { + state = Output; + } else if (arg == "n") { + state = NameSpace; + } else if (arg == "v") { + qWarning("dumpcpp: Version 1.0"); + return 0; + } else if (arg == "nometaobject") { + category |= NoMetaObject; + } else if (arg == "impl") { + category |= NoDeclaration; + } else if (arg == "decl") { + category |= NoImplementation; + } else if (arg == "donothing") { + category = DoNothing; + break; + } else if (arg == "compat") { + qax_dispatchEqualsIDispatch = true; + break; + } else if (arg == "getfile") { + state = GetTypeLib; + break; + } else if (arg == "h") { + qWarning("dumpcpp Version1.0\n\n" + "Generate a C++ namespace from a type library.\n\n" + "Usage:\n" + "dumpcpp input [-[-n <namespace>] [-o <filename>]\n\n" + " input: A type library file, type library ID, ProgID or CLSID\n\n" + "Optional parameters:\n" + " namespace: The name of the generated C++ namespace\n" + " filename: The file name (without extension) of the generated files\n" + "\n" + "Other parameters:\n" + " -nometaobject Don't generate meta object information (no .cpp file)\n" + " -impl Only generate the .cpp file\n" + " -decl Only generate the .h file\n" + " -compat Treat all coclass parameters as IDispatch\n" + "\n" + "Examples:\n" + " dumpcpp Outlook.Application -o outlook\n" + " dumpcpp {3B756301-0075-4E40-8BE8-5A81DE2426B7}\n" + "\n"); + return 0; + } + } else { + typeLib = arg; + } + break; + + case Output: + outname = arg; + state = Default; + break; + + case NameSpace: + nameSpace = arg; + state = Default; + break; + + case GetTypeLib: + typeLib = arg; + state = Default; + category = TypeLibID; + break; + default: + break; + } + } + + if (category == TypeLibID) { + QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes\\TypeLib\\") + + QString::fromLatin1(typeLib.constData()), QSettings::NativeFormat); + typeLib = QByteArray(); + QStringList codes = settings.childGroups(); + for (int c = 0; c < codes.count(); ++c) { + typeLib = settings.value(QLatin1String("/") + codes.at(c) + QLatin1String("/0/win32/.")).toByteArray(); + if (QFile::exists(QString::fromLatin1(typeLib))) { + break; + } + } + + if (!typeLib.isEmpty()) + fprintf(stdout, "\"%s\"\n", typeLib.data()); + return 0; + } + + if (category == DoNothing) + return 0; + + if (typeLib.isEmpty()) { + qWarning("dumpcpp: No object class or type library name provided.\n" + " Use -h for help."); + return -1; + } + + // not a file - search registry + if (!QFile::exists(QString::fromLatin1(typeLib.constData()))) { + bool isObject = false; + QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat); + + // regular string and not a file - must be ProgID + if (typeLib.at(0) != '{') { + CLSID clsid; + if (CLSIDFromProgID(reinterpret_cast<const wchar_t *>(QString(QLatin1String(typeLib)).utf16()), &clsid) != S_OK) { + qWarning("dumpcpp: '%s' is not a type library and not a registered ProgID", typeLib.constData()); + return -2; + } + QUuid uuid(clsid); + typeLib = uuid.toString().toLatin1(); + isObject = true; + } + + // check if CLSID + if (!isObject) { + QVariant test = settings.value(QLatin1String("/CLSID/") + + QString::fromLatin1(typeLib.constData()) + QLatin1String("/.")); + isObject = test.isValid(); + } + + // search typelib ID for CLSID + if (isObject) + typeLib = settings.value(QLatin1String("/CLSID/") + + QString::fromLatin1(typeLib.constData()) + QLatin1String("/Typelib/.")).toByteArray(); + + // interpret input as type library ID + QString key = QLatin1String("/TypeLib/") + QLatin1String(typeLib); + settings.beginGroup(key); + QStringList versions = settings.childGroups(); + QStringList codes; + if (versions.count()) { + settings.beginGroup(QLatin1String("/") + versions.last()); + codes = settings.childGroups(); + key += QLatin1String("/") + versions.last(); + settings.endGroup(); + } + settings.endGroup(); + + for (int c = 0; c < codes.count(); ++c) { + typeLib = settings.value(key + QLatin1String("/") + codes.at(c) + QLatin1String("/win32/.")).toByteArray(); + if (QFile::exists(QString::fromLatin1(typeLib.constData()))) { + break; + } + } + } + + if (!QFile::exists(QString::fromLatin1(typeLib.constData()))) { + qWarning("dumpcpp: type library '%s' not found", typeLib.constData()); + return -2; + } + + if (!generateTypeLibrary(typeLib, outname, (ObjectCategory)category)) { + qWarning("dumpcpp: error processing type library '%s'", typeLib.constData()); + return -1; + } + + return 0; +} diff --git a/tools/dumpdoc/dumpdoc.pro b/tools/dumpdoc/dumpdoc.pro new file mode 100644 index 0000000..3c93525 --- /dev/null +++ b/tools/dumpdoc/dumpdoc.pro @@ -0,0 +1,5 @@ +TEMPLATE = app + +CONFIG += console qaxcontainer + +SOURCES += main.cpp diff --git a/tools/dumpdoc/main.cpp b/tools/dumpdoc/main.cpp new file mode 100644 index 0000000..ae1f60f --- /dev/null +++ b/tools/dumpdoc/main.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QAxObject> +#include <QFile> +#include <QTextStream> +#include <qt_windows.h> + +QT_USE_NAMESPACE + +int main(int argc, char **argv) +{ + CoInitialize(0); + + enum State { + Default = 0, + OutOption + } state; + state = Default; + + QByteArray outname; + QByteArray object; + + for (int a = 1; a < argc; ++a) { + QByteArray arg(argv[a]); + const char first = arg[0]; + switch(state) { + case Default: + if (first == '-' || first == '/') { + arg = arg.mid(1); + arg.toLower(); + if (arg == "o") + state = OutOption; + else if (arg == "v") { + qWarning("dumpdoc: Version 1.0"); + return 0; + } else if (arg == "h") { + qWarning("dumpdoc Usage:\n\tdumpdoc object [-o <file>]" + " \n\tobject : object[/subobject]*" + " \n\tsubobject: property\n" + " \nexample:\n\tdumpdoc Outlook.Application/Session/CurrentUser -o outlook.html"); + return 0; + } + } else { + object = arg; + } + break; + case OutOption: + outname = arg; + state = Default; + break; + + default: + break; + } + } + + if (object.isEmpty()) { + qWarning("dumpdoc: No object name provided.\n" + " Use -h for help."); + return -1; + } + QFile outfile; + if (!outname.isEmpty()) { + outfile.setFileName(QString::fromLatin1(outname.constData())); + if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("dumpdoc: Could not open output file '%s'", outname.data()); + } + } else { + outfile.open(stdout, QIODevice::WriteOnly); + } + QTextStream out(&outfile); + + QByteArray subobject = object; + int index = subobject.indexOf('/'); + if (index != -1) + subobject = subobject.left(index); + + QAxObject topobject(QString::fromLatin1(subobject.constData())); + + if (topobject.isNull()) { + qWarning("dumpdoc: Could not instantiate COM object '%s'", subobject.data()); + return -2; + } + + QAxObject *axobject = &topobject; + while (index != -1 && axobject) { + index++; + subobject = object.mid(index); + if (object.indexOf('/', index) != -1) { + int oldindex = index; + index = object.indexOf('/', index); + subobject = object.mid(oldindex, index-oldindex); + } else { + index = -1; + } + + axobject = axobject->querySubObject(subobject); + } + if (!axobject || axobject->isNull()) { + qWarning("dumpdoc: Subobject '%s' does not exist in '%s'", subobject.data(), object.data()); + return -3; + } + + QString docu = axobject->generateDocumentation(); + out << docu; + return 0; +} diff --git a/tools/testcon/ambientproperties.cpp b/tools/testcon/ambientproperties.cpp new file mode 100644 index 0000000..f0bc017 --- /dev/null +++ b/tools/testcon/ambientproperties.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "ambientproperties.h" + +#include <QtGui> + +QT_BEGIN_NAMESPACE + +AmbientProperties::AmbientProperties(QWidget *parent) +: QDialog(parent), container(0) +{ + setupUi(this); + + connect(buttonClose, SIGNAL(clicked()), this, SLOT(close())); +} + +void AmbientProperties::setControl(QWidget *widget) +{ + container = widget; + + QColor c = container->palette().color(container->backgroundRole()); + QPalette p = backSample->palette(); p.setColor(backSample->backgroundRole(), c); backSample->setPalette(p); + + c = container->palette().color(container->foregroundRole()); + p = foreSample->palette(); p.setColor(foreSample->backgroundRole(), c); foreSample->setPalette(p); + + fontSample->setFont( container->font() ); + buttonEnabled->setChecked( container->isEnabled() ); + enabledSample->setEnabled( container->isEnabled() ); +} + +void AmbientProperties::on_buttonBackground_clicked() +{ + QColor c = QColorDialog::getColor(backSample->palette().color(backSample->backgroundRole()), this); + QPalette p = backSample->palette(); p.setColor(backSample->backgroundRole(), c); backSample->setPalette(p); + p = container->palette(); p.setColor(container->backgroundRole(), c); container->setPalette(p); + + if (QWorkspace *ws = qobject_cast<QWorkspace*>(container)) { + QWidgetList list( ws->windowList() ); + for (int i = 0; i < list.count(); ++i) { + QWidget *widget = list.at(i); + p = widget->palette(); p.setColor(widget->backgroundRole(), c); widget->setPalette(p); + } + } +} + +void AmbientProperties::on_buttonForeground_clicked() +{ + QColor c = QColorDialog::getColor(foreSample->palette().color(foreSample->backgroundRole()), this); + QPalette p = foreSample->palette(); p.setColor(foreSample->backgroundRole(), c); foreSample->setPalette(p); + p = container->palette(); p.setColor(container->foregroundRole(), c); container->setPalette(p); + + if (QWorkspace *ws = qobject_cast<QWorkspace*>(container)) { + QWidgetList list( ws->windowList() ); + for (int i = 0; i < list.count(); ++i) { + QWidget *widget = list.at(i); + p = widget->palette(); p.setColor(widget->foregroundRole(), c); widget->setPalette(p); + } + } +} + +void AmbientProperties::on_buttonFont_clicked() +{ + bool ok; + QFont f = QFontDialog::getFont( &ok, fontSample->font(), this ); + if ( !ok ) + return; + fontSample->setFont( f ); + container->setFont( f ); + + if (QWorkspace *ws = qobject_cast<QWorkspace*>(container)) { + QWidgetList list( ws->windowList() ); + for (int i = 0; i < list.count(); ++i) { + QWidget *widget = list.at(i); + widget->setFont( f ); + } + } +} + +void AmbientProperties::on_buttonEnabled_toggled(bool on) +{ + enabledSample->setEnabled( on ); + container->setEnabled( on ); +} + +QT_END_NAMESPACE diff --git a/tools/testcon/ambientproperties.h b/tools/testcon/ambientproperties.h new file mode 100644 index 0000000..501ad8f --- /dev/null +++ b/tools/testcon/ambientproperties.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AMBIENTPROPERTIES_H +#define AMBIENTPROPERTIES_H + +#include <QtCore/qglobal.h> + +#include "ui_ambientproperties.h" + +QT_BEGIN_NAMESPACE + +class AmbientProperties : public QDialog, Ui::AmbientProperties +{ + Q_OBJECT +public: + AmbientProperties(QWidget *parent); + + void setControl(QWidget *widget); + +public slots: + void on_buttonBackground_clicked(); + void on_buttonForeground_clicked(); + void on_buttonFont_clicked(); + void on_buttonEnabled_toggled(bool on); + +private: + QWidget *container; +}; + +QT_END_NAMESPACE + +#endif // AMBIENTPROPERTIES_H diff --git a/tools/testcon/ambientproperties.ui b/tools/testcon/ambientproperties.ui new file mode 100644 index 0000000..502c3b2 --- /dev/null +++ b/tools/testcon/ambientproperties.ui @@ -0,0 +1,299 @@ +<ui version="4.0" > + <author></author> + <comment>********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <exportmacro></exportmacro> + <class>AmbientProperties</class> + <widget class="QDialog" name="AmbientProperties" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>185</width> + <height>173</height> + </rect> + </property> + <property name="windowTitle" > + <string>Change Ambient Properties</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QGroupBox" name="boxProperties" > + <property name="title" > + <string>&Properties</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="TextLabel1" > + <property name="text" > + <string>Background:</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="TextLabel2" > + <property name="text" > + <string>Foreground:</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="TextLabel3" > + <property name="text" > + <string>Font:</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="TextLabel4" > + <property name="text" > + <string>Enabled:</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QFrame" name="foreSample" > + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QFrame" name="backSample" > + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + </widget> + </item> + <item row="0" column="2" > + <widget class="QToolButton" name="buttonBackground" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + <item row="1" column="2" > + <widget class="QToolButton" name="buttonForeground" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + <item row="2" column="2" > + <widget class="QToolButton" name="buttonFont" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>...</string> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QFrame" name="Frame6" > + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>0</number> + </property> + <item> + <widget class="QLabel" name="enabledSample" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="text" > + <string><sample></string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="3" column="2" > + <widget class="QToolButton" name="buttonEnabled" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>...</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QFrame" name="fontSample" > + <property name="frameShape" > + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLabel" name="TextLabel6" > + <property name="text" > + <string><sample></string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" > + <size> + <width>1</width> + <height>1</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="buttonClose" > + <property name="text" > + <string>C&lose</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <resources/> + <connections> + <connection> + <sender>buttonClose</sender> + <signal>clicked()</signal> + <receiver>AmbientProperties</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>141</x> + <y>150</y> + </hint> + <hint type="destinationlabel" > + <x>51</x> + <y>141</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/testcon/changeproperties.cpp b/tools/testcon/changeproperties.cpp new file mode 100644 index 0000000..ef896b6 --- /dev/null +++ b/tools/testcon/changeproperties.cpp @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "changeproperties.h" + +#include <QtGui> +#include <qt_windows.h> +#include <ActiveQt/ActiveQt> + +QT_BEGIN_NAMESPACE + +ChangeProperties::ChangeProperties(QWidget *parent) +: QDialog(parent), activex(0) +{ + setupUi(this); + + listProperties->setColumnCount(3); + listProperties->headerItem()->setText(0, QLatin1String("Name")); + listProperties->headerItem()->setText(1, QLatin1String("Type")); + listProperties->headerItem()->setText(2, QLatin1String("Value")); + + listEditRequests->setColumnCount(1); + listEditRequests->headerItem()->setText(0, QLatin1String("Name")); +} + +void ChangeProperties::setControl(QAxWidget *ax) +{ + activex = ax; + updateProperties(); +} + +void ChangeProperties::on_listProperties_currentItemChanged(QTreeWidgetItem *current) +{ + editValue->setEnabled(current != 0); + buttonSet->setEnabled(current != 0); + valueLabel->setEnabled(current != 0); + + if (!current) + return; + + editValue->setText(current->text(2)); + QString prop = current->text(0); + valueLabel->setText(prop + QLatin1String(" =")); + + const QMetaObject *mo = activex->metaObject(); + const QMetaProperty property = mo->property(mo->indexOfProperty(prop.toLatin1())); + + valueLabel->setEnabled(property.isWritable()); + editValue->setEnabled(property.isWritable()); + buttonSet->setEnabled(property.isWritable()); +} + +void ChangeProperties::on_buttonSet_clicked() +{ + QTreeWidgetItem *item = listProperties->currentItem(); + if (!item) + return; + + QString prop = item->text(0); + QVariant value = activex->property(prop.toLatin1()); + QVariant::Type type = value.type(); + if (!value.isValid()) { + const QMetaObject *mo = activex->metaObject(); + const QMetaProperty property = mo->property(mo->indexOfProperty(prop.toLatin1())); + type = QVariant::nameToType(property.typeName()); + } + switch (type) { + case QVariant::Color: + { + QColor col; + col.setNamedColor(editValue->text()); + if (col.isValid()) { + value = QVariant::fromValue(col); + } else { + QMessageBox::warning(this, tr("Can't parse input"), + tr("Failed to create a color from %1\n" + "The string has to be a valid color name (e.g. 'red')\n" + "or a RGB triple of format '#rrggbb'." + ).arg(editValue->text())); + } + } + break; + case QVariant::Font: + { + QFont fnt; + if (fnt.fromString(editValue->text())) { + value = QVariant::fromValue(fnt); + } else { + QMessageBox::warning(this, tr("Can't parse input"), + tr("Failed to create a font from %1\n" + "The string has to have a format family,<point size> or\n" + "family,pointsize,stylehint,weight,italic,underline,strikeout,fixedpitch,rawmode." + ).arg(editValue->text())); + } + } + break; + case QVariant::Pixmap: + { + QString fileName = editValue->text(); + if (fileName.isEmpty()) + fileName = QFileDialog::getOpenFileName(this); + QPixmap pm(fileName); + if (pm.isNull()) + return; + + value = QVariant::fromValue(pm); + } + break; + case QVariant::Bool: + { + QString txt = editValue->text().toLower(); + value = QVariant(txt != QLatin1String("0") && txt != QLatin1String("false")); + } + break; + case QVariant::List: + { + QStringList txtList = editValue->text().split(QRegExp(QLatin1String("[,;]"))); + QList<QVariant> varList; + for (int i = 0; i < txtList.count(); ++i) { + QVariant svar(txtList.at(i)); + QString str = svar.toString(); + str = str.trimmed(); + bool ok; + int n = str.toInt(&ok); + if (ok) { + varList << n; + continue; + } + double d = str.toDouble(&ok); + if (ok) { + varList << d; + continue; + } + varList << str; + } + value = varList; + } + break; + + default: + value = editValue->text(); + break; + } + + Q_ASSERT(activex->setProperty(prop.toLatin1(), value)); + updateProperties(); + listProperties->setCurrentItem(listProperties->findItems(prop, Qt::MatchExactly).at(0)); +} + +void ChangeProperties::on_listEditRequests_itemChanged(QTreeWidgetItem *item) +{ + if (!item) + return; + + QString property = item->text(0); + activex->setPropertyWritable(property.toLatin1(), item->checkState(0) == Qt::Checked); +} + + +void ChangeProperties::updateProperties() +{ + bool hasControl = activex && !activex->isNull(); + tabWidget->setEnabled(hasControl); + + listProperties->clear(); + listEditRequests->clear(); + if (hasControl) { + const QMetaObject *mo = activex->metaObject(); + const int numprops = mo->propertyCount(); + for (int i = mo->propertyOffset(); i < numprops; ++i) { + const QMetaProperty property = mo->property(i); + QTreeWidgetItem *item = new QTreeWidgetItem(listProperties); + item->setText(0, QString::fromLatin1(property.name())); + item->setText(1, QString::fromLatin1(property.typeName())); + if (!property.isDesignable()) { + item->setTextColor(0, Qt::gray); + item->setTextColor(1, Qt::gray); + item->setTextColor(2, Qt::gray); + } + QVariant var = activex->property(property.name()); + + switch (var.type()) { + case QVariant::Color: + { + QColor col = qvariant_cast<QColor>(var); + item->setText(2, col.name()); + } + break; + case QVariant::Font: + { + QFont fnt = qvariant_cast<QFont>(var); + item->setText(2, fnt.toString()); + } + break; + case QVariant::Bool: + { + item->setText(2, var.toBool() ? QLatin1String("true") : QLatin1String("false")); + } + break; + case QVariant::Pixmap: + { + QPixmap pm = qvariant_cast<QPixmap>(var); + item->setIcon(2, pm); + } + break; + case QVariant::List: + { + QList<QVariant> varList = var.toList(); + QStringList strList; + for (int i = 0; i < varList.count(); ++i) { + QVariant var = varList.at(i); + strList << var.toString(); + } + item->setText(2, strList.join(QLatin1String(", "))); + } + break; + case QVariant::Int: + if (property.isEnumType()) { + const QMetaEnum enumerator = mo->enumerator(mo->indexOfEnumerator(property.typeName())); + item->setText(2, QString::fromLatin1(enumerator.valueToKey(var.toInt()))); + break; + } + //FALLTHROUGH + default: + item->setText(2, var.toString()); + break; + } + + bool requesting = false; +#if 0 + { + void *argv[] = { &requesting }; + activex->qt_metacall(QMetaObject::Call(0x10000000) /*RequestingEdit*/, i, argv); + } +#endif + if (requesting) { + QTreeWidgetItem *check = new QTreeWidgetItem(listEditRequests); + check->setText(0, QString::fromLatin1(property.name())); + check->setCheckState(0, activex->propertyWritable(property.name()) ? Qt::Checked : Qt::Unchecked); + } + } + listProperties->setCurrentItem(listProperties->topLevelItem(0)); + } else { + editValue->clear(); + } +} + +QT_END_NAMESPACE diff --git a/tools/testcon/changeproperties.h b/tools/testcon/changeproperties.h new file mode 100644 index 0000000..c08e933 --- /dev/null +++ b/tools/testcon/changeproperties.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CHANGEPROPERTIES_H +#define CHANGEPROPERTIES_H + +#include <QtCore/qglobal.h> +#include "ui_changeproperties.h" + +QT_BEGIN_NAMESPACE + +class QAxWidget; + +class ChangeProperties : public QDialog, Ui::ChangeProperties +{ + Q_OBJECT +public: + ChangeProperties(QWidget *parent); + + void setControl(QAxWidget *control); + +public slots: + void updateProperties(); + +protected slots: + void on_listProperties_currentItemChanged(QTreeWidgetItem *current); + void on_listEditRequests_itemChanged(QTreeWidgetItem *item); + void on_buttonSet_clicked(); + +private: + QAxWidget *activex; +}; + +QT_END_NAMESPACE + +#endif // CHANGEPROPERTIES_H diff --git a/tools/testcon/changeproperties.ui b/tools/testcon/changeproperties.ui new file mode 100644 index 0000000..ef98f5c --- /dev/null +++ b/tools/testcon/changeproperties.ui @@ -0,0 +1,211 @@ +<ui version="4.0" > + <author></author> + <comment>********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <exportmacro></exportmacro> + <class>ChangeProperties</class> + <widget class="QDialog" name="ChangeProperties" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>728</width> + <height>584</height> + </rect> + </property> + <property name="windowTitle" > + <string>Change Control Properties</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTabWidget" name="tabWidget" > + <widget class="QWidget" name="propertiesTab" > + <attribute name="title" > + <string>&Properties</string> + </attribute> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTreeWidget" name="listProperties" > + <property name="rootIsDecorated" > + <bool>false</bool> + </property> + <column> + <property name="text" > + <string>Property</string> + </property> + </column> + <column> + <property name="text" > + <string>Type</string> + </property> + </column> + <column> + <property name="text" > + <string>Value</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QLabel" name="valueLabel" > + <property name="text" > + <string>Property &Value:</string> + </property> + <property name="buddy" > + <cstring>editValue</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="editValue" /> + </item> + <item> + <widget class="QToolButton" name="buttonSet" > + <property name="text" > + <string>&Set</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="requestTab" > + <attribute name="title" > + <string>Property Edit &Requests</string> + </attribute> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTreeWidget" name="listEditRequests" > + <column> + <property name="text" > + <string>Property</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" > + <size> + <width>1</width> + <height>1</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="buttonClose" > + <property name="text" > + <string>C&lose</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <resources/> + <connections> + <connection> + <sender>buttonClose</sender> + <signal>clicked()</signal> + <receiver>ChangeProperties</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>669</x> + <y>558</y> + </hint> + <hint type="destinationlabel" > + <x>566</x> + <y>551</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/testcon/controlinfo.cpp b/tools/testcon/controlinfo.cpp new file mode 100644 index 0000000..7b9dbb7 --- /dev/null +++ b/tools/testcon/controlinfo.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "controlinfo.h" + +#include <QtGui> + +QT_BEGIN_NAMESPACE + +ControlInfo::ControlInfo(QWidget *parent) + : QDialog(parent) +{ + setupUi(this); + + listInfo->setColumnCount(2); + listInfo->headerItem()->setText(0, tr("Item")); + listInfo->headerItem()->setText(1, tr("Details")); +} + +void ControlInfo::setControl(QWidget *activex) +{ + listInfo->clear(); + + const QMetaObject *mo = activex->metaObject(); + QTreeWidgetItem *group = new QTreeWidgetItem(listInfo); + group->setText(0, tr("Class Info")); + group->setText(1, QString::number(mo->classInfoCount())); + + QTreeWidgetItem *item = 0; + int i; + int count; + for (i = mo->classInfoOffset(); i < mo->classInfoCount(); ++i) { + const QMetaClassInfo info = mo->classInfo(i); + item = new QTreeWidgetItem(group); + item->setText(0, QString::fromLatin1(info.name())); + item->setText(1, QString::fromLatin1(info.value())); + } + group = new QTreeWidgetItem(listInfo); + group->setText(0, tr("Signals")); + + count = 0; + for (i = mo->methodOffset(); i < mo->methodCount(); ++i) { + const QMetaMethod method = mo->method(i); + if (method.methodType() == QMetaMethod::Signal) { + ++count; + item = new QTreeWidgetItem(group); + item->setText(0, QString::fromLatin1(method.signature())); + } + } + group->setText(1, QString::number(count)); + + group = new QTreeWidgetItem(listInfo); + group->setText(0, tr("Slots")); + + count = 0; + for (i = mo->methodOffset(); i < mo->methodCount(); ++i) { + const QMetaMethod method = mo->method(i); + if (method.methodType() == QMetaMethod::Slot) { + ++count; + item = new QTreeWidgetItem(group); + item->setText(0, QString::fromLatin1(method.signature())); + } + } + group->setText(1, QString::number(count)); + + group = new QTreeWidgetItem(listInfo); + group->setText(0, tr("Properties")); + + count = 0; + for (i = mo->propertyOffset(); i < mo->propertyCount(); ++i) { + ++count; + const QMetaProperty property = mo->property(i); + item = new QTreeWidgetItem(group); + item->setText(0, QString::fromLatin1(property.name())); + item->setText(1, QString::fromLatin1(property.typeName())); + if (!property.isDesignable()) { + item->setTextColor(0, Qt::gray); + item->setTextColor(1, Qt::gray); + } + } + group->setText(1, QString::number(count)); +} + +QT_END_NAMESPACE diff --git a/tools/testcon/controlinfo.h b/tools/testcon/controlinfo.h new file mode 100644 index 0000000..6f7c356 --- /dev/null +++ b/tools/testcon/controlinfo.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTROLINFO_H +#define CONTROLINFO_H + +#include <QtCore/qglobal.h> +#include "ui_controlinfo.h" + +QT_BEGIN_NAMESPACE + +class ControlInfo : public QDialog, Ui::ControlInfo +{ + Q_OBJECT +public: + ControlInfo(QWidget *parent); + + void setControl(QWidget *activex); +}; + +QT_END_NAMESPACE + +#endif // CONTROLINFO_H diff --git a/tools/testcon/controlinfo.ui b/tools/testcon/controlinfo.ui new file mode 100644 index 0000000..905ef43 --- /dev/null +++ b/tools/testcon/controlinfo.ui @@ -0,0 +1,134 @@ +<ui version="4.0" > + <author></author> + <comment>********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <exportmacro></exportmacro> + <class>ControlInfo</class> + <widget class="QDialog" name="ControlInfo" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>480</height> + </rect> + </property> + <property name="windowTitle" > + <string>Control Details</string> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTreeWidget" name="listInfo" > + <column> + <property name="text" > + <string>Item</string> + </property> + </column> + <column> + <property name="text" > + <string>Value</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" > + <size> + <width>1</width> + <height>1</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="buttonClose" > + <property name="text" > + <string>C&lose</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <resources/> + <connections> + <connection> + <sender>buttonClose</sender> + <signal>clicked()</signal> + <receiver>ControlInfo</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>536</x> + <y>457</y> + </hint> + <hint type="destinationlabel" > + <x>428</x> + <y>449</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/testcon/docuwindow.cpp b/tools/testcon/docuwindow.cpp new file mode 100644 index 0000000..14459b5 --- /dev/null +++ b/tools/testcon/docuwindow.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "docuwindow.h" +#include <QTextBrowser> +#include <QTextDocument> +#include <QToolBar> +#include <QToolButton> +#include <QFileDialog> +#include <QFile> +#include <QStatusBar> +#include <QPrinter> +#include <QPainter> +#include <QPrintDialog> +#include <QTextStream> + +QT_BEGIN_NAMESPACE + +static const char *filesave[] = { +" 14 14 4 1", +". c #040404", +"# c #808304", +"a c #bfc2bf", +"b c None", +"..............", +".#.aaaaaaaa.a.", +".#.aaaaaaaa...", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".##........##.", +".############.", +".##.........#.", +".##......aa.#.", +".##......aa.#.", +".##......aa.#.", +"b............." +}; + +static const char *fileprint[] = { +" 16 14 6 1", +". c #000000", +"# c #848284", +"a c #c6c3c6", +"b c #ffff00", +"c c #ffffff", +"d c None", +"ddddd.........dd", +"dddd.cccccccc.dd", +"dddd.c.....c.ddd", +"ddd.cccccccc.ddd", +"ddd.c.....c....d", +"dd.cccccccc.a.a.", +"d..........a.a..", +".aaaaaaaaaa.a.a.", +".............aa.", +".aaaaaa###aa.a.d", +".aaaaaabbbaa...d", +".............a.d", +"d.aaaaaaaaa.a.dd", +"dd...........ddd" +}; + + +DocuWindow::DocuWindow(const QString& docu, QWidget *parent, QWidget *source) + : QMainWindow(parent) +{ + setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(tr("%1 - Documentation").arg(source->windowTitle())); + + browser = new QTextBrowser(this); + browser->setHtml(docu); + + setCentralWidget(browser); + + QToolBar *fileTools = new QToolBar(tr("File Operations"), this); + fileTools->addAction(QPixmap(filesave), tr("Save File"), this, SLOT(save())); + fileTools->addAction(QPixmap(fileprint), tr("Print"), this, SLOT(print())); + + addToolBar(fileTools); + statusBar(); +} + +void DocuWindow::save() +{ + QString filename = QFileDialog::getSaveFileName(this); + + if (filename.isEmpty()) + return; + + QString text = browser->document()->toHtml(); + QFile f(filename); + if (!f.open(QIODevice::WriteOnly)) { + statusBar()->showMessage(tr("Could not write to %1").arg(filename), 2000); + return; + } + + QTextStream t(&f); + t << text; + f.close(); + + statusBar()->showMessage(tr("File %1 saved").arg(filename), 2000); +} + +void DocuWindow::print() +{ + QPrinter printer; + if (printer.printerName().isEmpty()) { + statusBar()->showMessage(tr("No printer installed"), 2000); + return; + } + + QPrintDialog printDialog(&printer, this); + if (!printDialog.exec()) { + statusBar()->showMessage(tr("Printing aborted"), 2000); + return; + } + + browser->document()->print(&printer); +} + +QT_END_NAMESPACE diff --git a/tools/testcon/docuwindow.h b/tools/testcon/docuwindow.h new file mode 100644 index 0000000..727534e --- /dev/null +++ b/tools/testcon/docuwindow.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DOCUWINDOW_H +#define DOCUWINDOW_H + +#include <QMainWindow> + +QT_BEGIN_NAMESPACE + +class QTextBrowser; + +class DocuWindow : public QMainWindow +{ + Q_OBJECT +public: + DocuWindow( const QString& docu, QWidget *parent, QWidget *source ); + +public slots: + void save(); + void print(); + +private: + QTextBrowser *browser; +}; + +QT_END_NAMESPACE + +#endif // DOCUWINDOW_H diff --git a/tools/testcon/invokemethod.cpp b/tools/testcon/invokemethod.cpp new file mode 100644 index 0000000..4e2be1a --- /dev/null +++ b/tools/testcon/invokemethod.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "invokemethod.h" + +#include <qt_windows.h> +#include <ActiveQt/ActiveQt> + +QT_BEGIN_NAMESPACE + +InvokeMethod::InvokeMethod(QWidget *parent) +: QDialog(parent), activex(0) +{ + setupUi(this); + + listParameters->setColumnCount(3); + listParameters->headerItem()->setText(0, tr("Parameter")); + listParameters->headerItem()->setText(1, tr("Type")); + listParameters->headerItem()->setText(2, tr("Value")); +} + +void InvokeMethod::setControl(QAxBase *ax) +{ + activex = ax; + bool hasControl = activex && !activex->isNull(); + labelMethods->setEnabled(hasControl); + comboMethods->setEnabled(hasControl); + buttonInvoke->setEnabled(hasControl); + boxParameters->setEnabled(hasControl); + + comboMethods->clear(); + listParameters->clear(); + + if (!hasControl) { + editValue->clear(); + return; + } + + const QMetaObject *mo = activex->metaObject(); + if (mo->methodCount()) { + for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) { + const QMetaMethod method = mo->method(i); + if (method.methodType() == QMetaMethod::Slot) + comboMethods->addItem(QString::fromLatin1(method.signature())); + } + comboMethods->model()->sort(0); + + on_comboMethods_activated(comboMethods->currentText()); + } +} + +void InvokeMethod::on_buttonInvoke_clicked() +{ + if (!activex) + return; + + on_buttonSet_clicked(); + QString method = comboMethods->currentText(); + QList<QVariant> vars; + + int itemCount = listParameters->topLevelItemCount(); + for (int i = 0; i < itemCount; ++i) { + QTreeWidgetItem *parameter = listParameters->topLevelItem(i); + vars << parameter->text(2); + } + QVariant result = activex->dynamicCall(method.toLatin1(), vars); + + int v = 0; + for (int i = 0; i < itemCount; ++i) { + QTreeWidgetItem *parameter = listParameters->topLevelItem(i); + parameter->setText(2, vars[v++].toString()); + } + + QString resString = result.toString(); + QString resType = QString::fromLatin1(result.typeName()); + editReturn->setText(resType + QLatin1String(" ") + resString); +} + +void InvokeMethod::on_comboMethods_activated(const QString &method) +{ + if (!activex) + return; + listParameters->clear(); + + const QMetaObject *mo = activex->metaObject(); + const QMetaMethod slot = mo->method(mo->indexOfSlot(method.toLatin1())); + QString signature = QString::fromLatin1(slot.signature()); + signature = signature.mid(signature.indexOf(QLatin1Char('(')) + 1); + signature.truncate(signature.length()-1); + + QList<QByteArray> pnames = slot.parameterNames(); + QList<QByteArray> ptypes = slot.parameterTypes(); + + for (int p = 0; p < ptypes.count(); ++p) { + QString ptype(QString::fromLatin1(ptypes.at(p))); + if (ptype.isEmpty()) + continue; + QString pname(QString::fromLatin1(pnames.at(p).constData())); + if (pname.isEmpty()) + pname = QString::fromLatin1("<unnamed %1>").arg(p); + QTreeWidgetItem *item = new QTreeWidgetItem(listParameters); + item->setText(0, pname); + item->setText(1, ptype); + } + + if (listParameters->topLevelItemCount()) + listParameters->setCurrentItem(listParameters->topLevelItem(0)); + editReturn->setText(QString::fromLatin1(slot.typeName())); +} + +void InvokeMethod::on_listParameters_currentItemChanged(QTreeWidgetItem *item) +{ + if (!activex) + return; + editValue->setEnabled(item != 0); + buttonSet->setEnabled(item != 0); + if (!item) + return; + editValue->setText(item->text(2)); +} + +void InvokeMethod::on_buttonSet_clicked() +{ + if (!activex) + return; + QTreeWidgetItem *item = listParameters->currentItem(); + if (!item) + return; + item->setText(2, editValue->text()); +} + +QT_END_NAMESPACE diff --git a/tools/testcon/invokemethod.h b/tools/testcon/invokemethod.h new file mode 100644 index 0000000..cbaaa0d --- /dev/null +++ b/tools/testcon/invokemethod.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INVOKEMETHOD_H +#define INVOKEMETHOD_H + +#include <QtCore/qglobal.h> +#include "ui_invokemethod.h" + +QT_BEGIN_NAMESPACE + +class QAxBase; + +class InvokeMethod : public QDialog, Ui::InvokeMethod +{ + Q_OBJECT +public: + InvokeMethod(QWidget *parent); + + void setControl(QAxBase *ax); + +protected slots: + void on_buttonInvoke_clicked(); + void on_buttonSet_clicked(); + + void on_comboMethods_activated(const QString &method); + void on_listParameters_currentItemChanged(QTreeWidgetItem *item); + +private: + QAxBase *activex; +}; + +QT_END_NAMESPACE + +#endif // INVOKEMETHOD_H diff --git a/tools/testcon/invokemethod.ui b/tools/testcon/invokemethod.ui new file mode 100644 index 0000000..f912b06 --- /dev/null +++ b/tools/testcon/invokemethod.ui @@ -0,0 +1,270 @@ +<ui version="4.0" > + <author></author> + <comment>********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <exportmacro></exportmacro> + <class>InvokeMethod</class> + <widget class="QDialog" name="InvokeMethod" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>503</width> + <height>416</height> + </rect> + </property> + <property name="windowTitle" > + <string>Invoke Methods</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="0" colspan="2" > + <widget class="QGroupBox" name="boxParameters" > + <property name="title" > + <string>&Parameter List</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>11</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="0" column="0" colspan="3" > + <widget class="QTreeWidget" name="listParameters" > + <property name="rootIsDecorated" > + <bool>false</bool> + </property> + <column> + <property name="text" > + <string>Parameter</string> + </property> + </column> + <column> + <property name="text" > + <string>Type</string> + </property> + </column> + <column> + <property name="text" > + <string>Value</string> + </property> + </column> + </widget> + </item> + <item row="1" column="2" > + <widget class="QToolButton" name="buttonSet" > + <property name="text" > + <string>&Set</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="editValue" /> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="TextLabel3" > + <property name="text" > + <string>Parameter &Value:</string> + </property> + <property name="buddy" > + <cstring>editValue</cstring> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="0" colspan="2" > + <layout class="QGridLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="1" column="1" > + <widget class="QLineEdit" name="editReturn" > + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QComboBox" name="comboMethods" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable" > + <bool>true</bool> + </property> + <property name="insertPolicy" > + <enum>QComboBox::NoInsert</enum> + </property> + <property name="autoCompletion" > + <bool>true</bool> + </property> + <property name="duplicatesEnabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="labelMethods" > + <property name="text" > + <string>&Method Name:</string> + </property> + <property name="buddy" > + <cstring>comboMethods</cstring> + </property> + </widget> + </item> + <item row="0" column="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="TextLabel1" > + <property name="text" > + <string>Returned Value:</string> + </property> + </widget> + </item> + <item row="0" column="3" > + <widget class="QPushButton" name="buttonInvoke" > + <property name="text" > + <string>&Invoke</string> + </property> + <property name="default" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="2" colspan="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" > + <size> + <width>111</width> + <height>21</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="2" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType" > + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" > + <size> + <width>361</width> + <height>21</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <widget class="QPushButton" name="buttonClose" > + <property name="text" > + <string>C&lose</string> + </property> + <property name="autoDefault" > + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <resources/> + <connections> + <connection> + <sender>buttonClose</sender> + <signal>clicked()</signal> + <receiver>InvokeMethod</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>453</x> + <y>396</y> + </hint> + <hint type="destinationlabel" > + <x>327</x> + <y>384</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/testcon/main.cpp b/tools/testcon/main.cpp new file mode 100644 index 0000000..39887c2 --- /dev/null +++ b/tools/testcon/main.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" + +#include <QApplication> +#include <QAxFactory> + +QAXFACTORY_DEFAULT(MainWindow, + QLatin1String("{5f5ce700-48a8-47b1-9b06-3b7f79e41d7c}"), + QLatin1String("{3fc86f5f-8b15-4428-8f6b-482bae91f1ae}"), + QLatin1String("{02a268cd-24b4-4fd9-88ff-b01b683ef39d}"), + QLatin1String("{4a43e44d-9d1d-47e5-a1e5-58fe6f7be0a4}"), + QLatin1String("{16ee5998-77d2-412f-ad91-8596e29f123f}")) + +QT_USE_NAMESPACE + +int main( int argc, char **argv ) +{ + QApplication app( argc, argv ); + + MainWindow mw; + mw.show(); + + return app.exec();; +} diff --git a/tools/testcon/mainwindow.cpp b/tools/testcon/mainwindow.cpp new file mode 100644 index 0000000..2090c19 --- /dev/null +++ b/tools/testcon/mainwindow.cpp @@ -0,0 +1,461 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "changeproperties.h" +#include "invokemethod.h" +#include "ambientproperties.h" +#include "controlinfo.h" +#include "docuwindow.h" + +#include <QtGui> +#include <qt_windows.h> +#include <ActiveQt/ActiveQt> + +QT_BEGIN_NAMESPACE + +QAxObject *ax_mainWindow = 0; + +static QTextEdit *debuglog = 0; + +static void redirectDebugOutput(QtMsgType type, const char*msg) +{ + Q_UNUSED(type); + debuglog->append(QLatin1String(msg)); +} + +QT_END_NAMESPACE + +QT_USE_NAMESPACE + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ + setupUi(this); + setObjectName(QLatin1String("MainWindow")); + + QAxScriptManager::registerEngine(QLatin1String("PerlScript"), QLatin1String(".pl")); + QAxScriptManager::registerEngine(QLatin1String("Python"), QLatin1String(".py")); + + dlgInvoke = 0; + dlgProperties = 0; + dlgAmbient = 0; + scripts = 0; + debuglog = logDebug; + oldDebugHandler = qInstallMsgHandler(redirectDebugOutput); + QHBoxLayout *layout = new QHBoxLayout(Workbase); + workspace = new QWorkspace(Workbase); + layout->addWidget(workspace); + layout->setMargin(0); + + connect(workspace, SIGNAL(windowActivated(QWidget*)), this, SLOT(updateGUI())); + connect(actionFileExit, SIGNAL(triggered()), qApp, SLOT(quit())); +} + +MainWindow::~MainWindow() +{ + qInstallMsgHandler(oldDebugHandler); + debuglog = 0; +} + + +void MainWindow::on_actionFileNew_triggered() +{ + QAxSelect select(this); + if (select.exec()) { + QAxWidget *container = new QAxWidget(workspace); + container->setAttribute(Qt::WA_DeleteOnClose); + container->setControl(select.clsid()); + container->setObjectName(container->windowTitle()); + workspace->addWindow(container); + container->show(); + } + updateGUI(); +} + +void MainWindow::on_actionFileLoad_triggered() +{ + QString fname = QFileDialog::getOpenFileName(this, tr("Load"), QString(), QLatin1String("*.qax")); + if (fname.isEmpty()) + return; + + QFile file(fname); + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::information(this, tr("Error Loading File"), tr("The file could not be opened for reading.\n%1").arg(fname)); + return; + } + + QAxWidget *container = new QAxWidget(workspace); + workspace->addWindow(container); + + QDataStream d(&file); + d >> *container; + + container->setObjectName(container->windowTitle()); + container->show(); + + updateGUI(); +} + +void MainWindow::on_actionFileSave_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + QString fname = QFileDialog::getSaveFileName(this, tr("Save"), QString(), QLatin1String("*.qax")); + if (fname.isEmpty()) + return; + + QFile file(fname); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::information(this, tr("Error Saving File"), tr("The file could not be opened for writing.\n%1").arg(fname)); + return; + } + QDataStream d(&file); + d << *container; +} + + +void MainWindow::on_actionContainerSet_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + QAxSelect select(this); + if (select.exec()) + container->setControl(select.clsid()); + updateGUI(); +} + +void MainWindow::on_actionContainerClear_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (container) + container->clear(); + updateGUI(); +} + +void MainWindow::on_actionContainerProperties_triggered() +{ + if (!dlgAmbient) { + dlgAmbient = new AmbientProperties(this); + dlgAmbient->setControl(workspace); + } + dlgAmbient->show(); +} + + +void MainWindow::on_actionControlInfo_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + ControlInfo info(this); + info.setControl(container); + info.exec(); +} + +void MainWindow::on_actionControlProperties_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + if (!dlgProperties) { + dlgProperties = new ChangeProperties(this); + connect(container, SIGNAL(propertyChanged(QString)), dlgProperties, SLOT(updateProperties())); + } + dlgProperties->setControl(container); + dlgProperties->show(); +} + +void MainWindow::on_actionControlMethods_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + if (!dlgInvoke) + dlgInvoke = new InvokeMethod(this); + dlgInvoke->setControl(container); + dlgInvoke->show(); +} + +void MainWindow::on_VerbMenu_aboutToShow() +{ + VerbMenu->clear(); + + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + QStringList verbs = container->verbs(); + for (int i = 0; i < verbs.count(); ++i) { + VerbMenu->addAction(verbs.at(i)); + } + + if (!verbs.count()) { // no verbs? + VerbMenu->addAction(tr("-- Object does not support any verbs --"))->setEnabled(false); + } +} + +void MainWindow::on_VerbMenu_triggered(QAction *action) +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + container->doVerb(action->text()); +} + +void MainWindow::on_actionControlDocumentation_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + QString docu = container->generateDocumentation(); + if (docu.isEmpty()) + return; + + DocuWindow *docwindow = new DocuWindow(docu, workspace, container); + workspace->addWindow(docwindow); + docwindow->show(); +} + + +void MainWindow::on_actionControlPixmap_triggered() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + QPixmap pm = QPixmap::grabWidget(container); + + QLabel *label = new QLabel(workspace); + label->setAttribute(Qt::WA_DeleteOnClose); + label->setPixmap(pm); + label->setWindowTitle(tr("%1 - Pixmap").arg(container->windowTitle())); + + workspace->addWindow(label); + label->show(); +} + +void MainWindow::on_actionScriptingRun_triggered() +{ +#ifndef QT_NO_QAXSCRIPT + if (!scripts) + return; + + // If we have only one script loaded we can use the cool dialog + QStringList scriptList = scripts->scriptNames(); + if (scriptList.count() == 1) { + InvokeMethod scriptInvoke(this); + scriptInvoke.setWindowTitle(tr("Execute Script Function")); + scriptInvoke.setControl(scripts->script(scriptList[0])->scriptEngine()); + scriptInvoke.exec(); + return; + } + + bool ok = false; + QStringList macroList = scripts->functions(QAxScript::FunctionNames); + QString macro = QInputDialog::getItem(this, tr("Select Macro"), tr("Macro:"), macroList, 0, true, &ok); + + if (!ok) + return; + + QVariant result = scripts->call(macro); + if (result.isValid()) + logMacros->append(tr("Return value of %1: %2").arg(macro).arg(result.toString())); +#endif +} + +void MainWindow::on_actionScriptingLoad_triggered() +{ +#ifndef QT_NO_QAXSCRIPT + QString file = QFileDialog::getOpenFileName(this, tr("Open Script"), QString(), QAxScriptManager::scriptFileFilter()); + + if (file.isEmpty()) + return; + + if (!scripts) { + scripts = new QAxScriptManager(this); + scripts->addObject(this); + } + + QWidgetList widgets = workspace->windowList(); + QWidgetList::Iterator it(widgets.begin()); + while (it != widgets.end()) { + QAxBase *ax = (QAxBase*)(*it)->qt_metacast("QAxBase"); + ++it; + if (!ax) + continue; + scripts->addObject(ax); + } + + QAxScript *script = scripts->load(file, file); + if (script) { + connect(script, SIGNAL(error(int,QString,int,QString)), + this, SLOT(logMacro(int,QString,int,QString))); + actionScriptingRun->setEnabled(true); + } +#else + QMessageBox::information(this, tr("Function not available"), + tr("QAxScript functionality is not available with this compiler.")); +#endif +} + +void MainWindow::updateGUI() +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + + bool hasControl = container && !container->isNull(); + actionFileNew->setEnabled(true); + actionFileLoad->setEnabled(true); + actionFileSave->setEnabled(hasControl); + actionContainerSet->setEnabled(container != 0); + actionContainerClear->setEnabled(hasControl); + actionControlProperties->setEnabled(hasControl); + actionControlMethods->setEnabled(hasControl); + actionControlInfo->setEnabled(hasControl); + actionControlDocumentation->setEnabled(hasControl); + actionControlPixmap->setEnabled(hasControl); + VerbMenu->setEnabled(hasControl); + if (dlgInvoke) + dlgInvoke->setControl(hasControl ? container : 0); + if (dlgProperties) + dlgProperties->setControl(hasControl ? container : 0); + + QWidgetList list = workspace->windowList(); + QWidgetList::Iterator it = list.begin(); + while (it != list.end()) { + QWidget *container = *it; + + QAxWidget *ax = qobject_cast<QAxWidget*>(container); + if (ax) { + container->disconnect(SIGNAL(signal(QString,int,void*))); + if (actionLogSignals->isChecked()) + connect(container, SIGNAL(signal(QString,int,void*)), this, SLOT(logSignal(QString,int,void*))); + + container->disconnect(SIGNAL(exception(int,QString,QString,QString))); + connect(container, SIGNAL(exception(int,QString,QString,QString)), + this, SLOT(logException(int,QString,QString,QString))); + + container->disconnect(SIGNAL(propertyChanged(QString))); + if (actionLogProperties->isChecked()) + connect(container, SIGNAL(propertyChanged(QString)), this, SLOT(logPropertyChanged(QString))); + container->blockSignals(actionFreezeEvents->isChecked()); + } + + ++it; + } +} + + +void MainWindow::logPropertyChanged(const QString &prop) +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + QVariant var = container->property(prop.toLatin1()); + logProperties->append(tr("%1: Property Change: %2 - { %3 }").arg(container->windowTitle(), prop, var.toString())); +} + +void MainWindow::logSignal(const QString &signal, int argc, void *argv) +{ + QAxWidget *container = qobject_cast<QAxWidget*>(workspace->activeWindow()); + if (!container) + return; + + QString paramlist; + VARIANT *params = (VARIANT*)argv; + for (int a = argc-1; a >= 0; --a) { + if (a == argc-1) + paramlist = QLatin1String(" - {"); + QVariant qvar = VARIANTToQVariant(params[a], 0); + paramlist += QLatin1String(" ") + qvar.toString(); + if (a > 0) + paramlist += QLatin1String(","); + else + paramlist += QLatin1String(" "); + } + if (argc) + paramlist += QLatin1String("}"); + logSignals->append(container->windowTitle() + QLatin1String(": ") + signal + paramlist); +} + +void MainWindow::logException(int code, const QString&source, const QString&desc, const QString&help) +{ + Q_UNUSED(desc); + QAxWidget *container = qobject_cast<QAxWidget*>(sender()); + if (!container) + return; + + QString str = tr("%1: Exception code %2 thrown by %3"). + arg(container->windowTitle()).arg(code).arg(source); + logDebug->append(str); + logDebug->append(tr("\tDescription: %1").arg(desc)); + + if (!help.isEmpty()) + logDebug->append(tr("\tHelp available at %1").arg(help)); + else + logDebug->append(tr("\tNo help available.")); +} + +void MainWindow::logMacro(int code, const QString &description, int sourcePosition, const QString &sourceText) +{ + /* FIXME This needs to be rewritten to not use string concatentation, such + * that it can be translated in a sane way. */ + QString message = tr("Script: "); + if (code) + message += QString::number(code) + QLatin1String(" "); + message += QLatin1String("'") + description + QLatin1String("'"); + if (sourcePosition) + message += tr(" at position ") + QString::number(sourcePosition); + if (!sourceText.isEmpty()) + message += QLatin1String(" '") + sourceText + QLatin1String("'"); + + logMacros->append(message); +} diff --git a/tools/testcon/mainwindow.h b/tools/testcon/mainwindow.h new file mode 100644 index 0000000..a2abc37 --- /dev/null +++ b/tools/testcon/mainwindow.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "ui_mainwindow.h" + +QT_BEGIN_NAMESPACE + +class InvokeMethod; +class ChangeProperties; +class AmbientProperties; +class QAxScriptManager; + +class QWorkspace; + +QT_END_NAMESPACE + +QT_USE_NAMESPACE + + +class MainWindow : public QMainWindow, public Ui::MainWindow +{ + Q_OBJECT +public: + MainWindow(QWidget *parent = 0); + ~MainWindow(); + +protected slots: + void on_actionFileNew_triggered(); + void on_actionFileLoad_triggered(); + void on_actionFileSave_triggered(); + + void on_actionContainerSet_triggered(); + void on_actionContainerClear_triggered(); + void on_actionContainerProperties_triggered(); + + void on_actionControlInfo_triggered(); + void on_actionControlDocumentation_triggered(); + void on_actionControlPixmap_triggered(); + void on_actionControlProperties_triggered(); + void on_actionControlMethods_triggered(); + void on_VerbMenu_aboutToShow(); + + void on_actionScriptingLoad_triggered(); + void on_actionScriptingRun_triggered(); + +private: + InvokeMethod *dlgInvoke; + ChangeProperties *dlgProperties; + AmbientProperties *dlgAmbient; + QAxScriptManager *scripts; + QWorkspace *workspace; + + QtMsgHandler oldDebugHandler; + +private slots: + void updateGUI(); + void logPropertyChanged(const QString &prop); + void logSignal(const QString &signal, int argc, void *argv); + void logException(int code, const QString&source, const QString&desc, const QString&help); + void logMacro(int code, const QString &description, int sourcePosition, const QString &sourceText); + + void on_VerbMenu_triggered(QAction *action); +}; + +#endif // MAINWINDOW_H diff --git a/tools/testcon/mainwindow.ui b/tools/testcon/mainwindow.ui new file mode 100644 index 0000000..54889f0 --- /dev/null +++ b/tools/testcon/mainwindow.ui @@ -0,0 +1,682 @@ +<ui version="4.0" stdsetdef="1" > + <author></author> + <comment>********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +*********************************************************************</comment> + <exportmacro></exportmacro> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow" > + <property name="objectName" > + <string notr="true" >MainWindow</string> + </property> + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>929</width> + <height>620</height> + </rect> + </property> + <property name="windowTitle" > + <string>ActiveX Control Test Container</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QFrame" name="Frame" > + <property name="objectName" > + <string notr="true" >Frame</string> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape" > + <enum>StyledPanel</enum> + </property> + <property name="frameShadow" > + <enum>Sunken</enum> + </property> + <layout class="QVBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>0</number> + </property> + <item> + <widget class="QSplitter" name="Splitter2" > + <property name="objectName" > + <string notr="true" >Splitter2</string> + </property> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <widget class="QFrame" name="Workbase" > + <property name="objectName" > + <string notr="true" >Workbase</string> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape" > + <enum>NoFrame</enum> + </property> + <property name="frameShadow" > + <enum>Raised</enum> + </property> + </widget> + <widget class="QTabWidget" name="TabWidget2" > + <property name="objectName" > + <string notr="true" >TabWidget2</string> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <widget class="QWidget" name="logSignalsTab" > + <property name="objectName" > + <string notr="true" >logSignalsTab</string> + </property> + <attribute name="title" > + <string>Signal log</string> + </attribute> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTextEdit" name="logSignals" > + <property name="objectName" > + <string notr="true" >logSignals</string> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="logPropertiesTab" > + <property name="objectName" > + <string notr="true" >logPropertiesTab</string> + </property> + <attribute name="title" > + <string>Property log</string> + </attribute> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTextEdit" name="logProperties" > + <property name="objectName" > + <string notr="true" >logProperties</string> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="TabPage" > + <property name="objectName" > + <string notr="true" >TabPage</string> + </property> + <attribute name="title" > + <string>Macro Log</string> + </attribute> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QTextEdit" name="logMacros" > + <property name="objectName" > + <string notr="true" >logMacros</string> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="logDebugTab" > + <property name="objectName" > + <string notr="true" >logDebugTab</string> + </property> + <attribute name="title" > + <string>Debug log</string> + </attribute> + <layout class="QHBoxLayout" > + <property name="objectName" > + <string notr="true" >unnamed</string> + </property> + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QTextEdit" name="logDebug" > + <property name="objectName" > + <string notr="true" >logDebug</string> + </property> + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QToolBar" name="Toolbar_2" > + <property name="objectName" > + <string notr="true" >Toolbar_2</string> + </property> + <property name="windowTitle" > + <string>Toolbar_2</string> + </property> + <addaction name="actionFileNew" /> + <addaction name="actionControlMethods" /> + <addaction name="actionControlProperties" /> + </widget> + <widget class="QMenuBar" name="menubar" > + <property name="objectName" > + <string notr="true" >menubar</string> + </property> + <widget class="QMenu" name="FileMenu" > + <property name="objectName" > + <string notr="true" >FileMenu</string> + </property> + <property name="title" > + <string>&File</string> + </property> + <addaction name="actionFileNew" /> + <addaction name="actionFileLoad" /> + <addaction name="actionFileSave" /> + <addaction name="separator" /> + <addaction name="actionFileExit" /> + </widget> + <widget class="QMenu" name="ContainerMenu" > + <property name="objectName" > + <string notr="true" >ContainerMenu</string> + </property> + <property name="title" > + <string>Con&tainer</string> + </property> + <addaction name="actionContainerSet" /> + <addaction name="actionContainerClear" /> + <addaction name="separator" /> + <addaction name="actionContainerProperties" /> + </widget> + <widget class="QMenu" name="ControlMenu" > + <property name="objectName" > + <string notr="true" >ControlMenu</string> + </property> + <property name="title" > + <string>&Control</string> + </property> + <widget class="QMenu" name="VerbMenu" > + <property name="objectName" > + <string notr="true" >VerbMenu</string> + </property> + <property name="title" > + <string>&Verbs...</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + <addaction name="actionControlMethods" /> + <addaction name="actionControlProperties" /> + <addaction name="VerbMenu" /> + <addaction name="separator" /> + <addaction name="actionControlInfo" /> + <addaction name="actionControlDocumentation" /> + <addaction name="actionControlPixmap" /> + </widget> + <widget class="QMenu" name="ScriptMenu" > + <property name="objectName" > + <string notr="true" >ScriptMenu</string> + </property> + <property name="title" > + <string>&Scripting</string> + </property> + <addaction name="actionScriptingLoad" /> + <addaction name="actionScriptingRun" /> + </widget> + <widget class="QMenu" name="OptionsMenu" > + <property name="objectName" > + <string notr="true" >OptionsMenu</string> + </property> + <property name="title" > + <string>&Options</string> + </property> + <widget class="QMenu" name="LoggingMenu" > + <property name="objectName" > + <string notr="true" >LoggingMenu</string> + </property> + <property name="title" > + <string>Log...</string> + </property> + <addaction name="actionLogSignals" /> + <addaction name="actionLogProperties" /> + </widget> + <addaction name="actionFreezeEvents" /> + <addaction name="actionGroupLogging" /> + <addaction name="LoggingMenu" /> + </widget> + <addaction name="FileMenu" /> + <addaction name="ContainerMenu" /> + <addaction name="ControlMenu" /> + <addaction name="ScriptMenu" /> + <addaction name="OptionsMenu" /> + </widget> + <action name="actionFileExit" > + <property name="objectName" > + <string>actionFileExit</string> + </property> + <property name="iconText" > + <string>Exit</string> + </property> + <property name="text" > + <string>E&xit</string> + </property> + </action> + <action name="actionContainerSet" > + <property name="objectName" > + <string>actionContainerSet</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="iconText" > + <string>Set Control</string> + </property> + <property name="text" > + <string>&Set Control</string> + </property> + <property name="shortcut" > + <string>Ctrl+S</string> + </property> + </action> + <action name="actionControlMethods" > + <property name="objectName" > + <string>actionControlMethods</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="icon" > + <iconset>image0</iconset> + </property> + <property name="iconText" > + <string>Invoke Methods</string> + </property> + <property name="text" > + <string>Invoke &Methods</string> + </property> + <property name="shortcut" > + <string>Ctrl+M</string> + </property> + </action> + <action name="actionControlProperties" > + <property name="objectName" > + <string>actionControlProperties</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="icon" > + <iconset>image1</iconset> + </property> + <property name="iconText" > + <string>Change Properties</string> + </property> + <property name="text" > + <string>Change &Properties</string> + </property> + <property name="shortcut" > + <string>Ctrl+P</string> + </property> + </action> + <action name="actionContainerClear" > + <property name="objectName" > + <string>actionContainerClear</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="iconText" > + <string>Clear Control</string> + </property> + <property name="text" > + <string>C&lear Control</string> + </property> + <property name="shortcut" > + <string/> + </property> + </action> + <action name="actionContainerProperties" > + <property name="objectName" > + <string>actionContainerProperties</string> + </property> + <property name="iconText" > + <string>Ambient Properties</string> + </property> + <property name="text" > + <string>Ambient &Properties</string> + </property> + <property name="shortcut" > + <string>Ctrl+A</string> + </property> + </action> + <action name="actionControlInfo" > + <property name="objectName" > + <string>actionControlInfo</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="iconText" > + <string>Details</string> + </property> + <property name="text" > + <string>&Details</string> + </property> + <property name="shortcut" > + <string>Ctrl+I</string> + </property> + </action> + <action name="actionFileSave" > + <property name="objectName" > + <string>actionFileSave</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="iconText" > + <string>Save Control</string> + </property> + <property name="text" > + <string>&Save Control</string> + </property> + </action> + <action name="actionFileLoad" > + <property name="objectName" > + <string>actionFileLoad</string> + </property> + <property name="iconText" > + <string>Load Control</string> + </property> + <property name="text" > + <string>&Load Control</string> + </property> + </action> + <action name="actionFreezeEvents" > + <property name="objectName" > + <string>actionFreezeEvents</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="iconText" > + <string>Freeze Events</string> + </property> + <property name="text" > + <string>&Freeze Events</string> + </property> + </action> + <action name="actionFileNew" > + <property name="objectName" > + <string>actionFileNew</string> + </property> + <property name="icon" > + <iconset>image2</iconset> + </property> + <property name="iconText" > + <string>Insert Control</string> + </property> + <property name="text" > + <string>&Insert Control</string> + </property> + <property name="shortcut" > + <string>Ctrl+N</string> + </property> + </action> + <action name="actionControlDocumentation" > + <property name="objectName" > + <string>actionControlDocumentation</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="iconText" > + <string>Show Documentation</string> + </property> + <property name="text" > + <string>Show D&ocumentation</string> + </property> + <property name="shortcut" > + <string>Ctrl+D</string> + </property> + </action> + <action name="actionControlPixmap" > + <property name="objectName" > + <string>actionControlPixmap</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="iconText" > + <string>Render to Pixmap</string> + </property> + <property name="text" > + <string>Render to Pi&xmap</string> + </property> + <property name="shortcut" > + <string>Ctrl+X</string> + </property> + </action> + <action name="actionScriptingLoad" > + <property name="objectName" > + <string>actionScriptingLoad</string> + </property> + <property name="iconText" > + <string>Load Script</string> + </property> + <property name="text" > + <string>&Load Script</string> + </property> + </action> + <action name="actionScriptingRun" > + <property name="objectName" > + <string>actionScriptingRun</string> + </property> + <property name="enabled" > + <bool>false</bool> + </property> + <property name="iconText" > + <string>Run Macro</string> + </property> + <property name="text" > + <string>&Run Macro...</string> + </property> + </action> + <actiongroup name="actionGroupLogging" > + <action name="actionLogSignals" > + <property name="objectName" > + <string>actionLogSignals</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="checked" > + <bool>true</bool> + </property> + <property name="iconText" > + <string>Signals</string> + </property> + <property name="text" > + <string>&Signals</string> + </property> + </action> + <action name="actionLogProperties" > + <property name="objectName" > + <string>actionLogProperties</string> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + <property name="checked" > + <bool>true</bool> + </property> + <property name="iconText" > + <string>Properties</string> + </property> + <property name="text" > + <string>&Properties</string> + </property> + </action> + <property name="objectName" > + <string>actionGroupLogging</string> + </property> + <property name="exclusive" > + <bool>false</bool> + </property> + </actiongroup> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <images> + <image name="image0" > + <data format="XPM.GZ" length="3502" >789cdd95c96e1c371086ef7a8a81eb6604e56e92bd21c84192175996648d6559b2831cd85cb4ef23d95290770fe72f36e3003ee41220485373f8543f975a587cf17c76b8bb3d7bfe62e56e6117276ee68eededecb9bfbfb878fcf5b75f7e5f79a6d42cfdd54d3553cf7e5a79365fccdc6ce7ea322cc19e26a0aa51aaeb964c31b3ee46d8a9b05b32b7994d27f3178523ecbb99bbbe87fdaef000be06b7ca0e067c9b791c5af04d6637c87e8f99fde0c11edc6935c2193e01f7dab91a1cc083314ef4c7e0b15141ece29f6b4c68c047998720fb7d01473d8e60b24bae2b1d1cf416faba36cacbfe1b99b597f5e04f6d4c081af335b86f5c80ff74091eda3a20beb40376ad8b381fbd0487ce44890f83a3a92cf6a3fd25abca682beb7d15ee42141ec0e90016fed366e6c6223ff498b91d2b30ceab5462d93f1416ff9accdd28e741bc9531e388fcd3c7c292fff7e0c67827febf05b74de5e47c3db84b2cfedf64ae9dc4df1496fc55e0bed15eceb75758ce578387a6f1a81fda288cfa639db9f5d89f55610b7d07b64defc51f3f71407c18f95163aa0fd9ff43662bf543a867e51b9ff3391696fa719943107f241ea189926f96fc84b68a92df3785113fdece5c47a9af77e09818fef2566615e5bea1de75ddb6c284fbaa753b487df03770d34ef532070f5d9bf90aecbb18253ec8bf317d88f08f719f4d3ba8cca83f330c5d147f5f67ee33239fc60e6366ec6fc6c10933fa87f1b6ca7c9fb98e12af0770b05a98d05f4cb42633eaade9c6364afe5e816d2a47e94fb86f9dafea0af1b617e05018fe76b1f0f9927b5df80c1c2a55213f16fd607085d14f6c5d18f7c7b6f5584b3da03e6d5718f567fb494f5bc2c5be061e26b6a847ebea3460477c6c2c8cfa18abb2de2ab8ae7d2df15907ab625f084f768bfa1c4d61d4ef38d4a196787e02db693e8bbef84f88d718ea584b7f417cdd5fe7c1fbe14a7c08f7d9a9e581c088af3385515fae298cfcbbb6d295f49327e1c9ce9fc1dd6467dc1fd7173dfab9f3aa5672dfd06f5c2c76f4575fa9f481b19eaf0be37df46a623e04ebc2e8b7de28ad64ff03705318f7c1b73a7d60c4d35b6514fa29a19ffa7162467ff7ae30f2e17d39afecef8b1dfdd7c7c2a8ff6074aba53f20fea1cc679bd954a2473f0d41754ade7ff497d8a85e49ffc47b145b6db5f403f817fb62477ca29dd623f49fe8d4a0a4dff4994725fde25a58a701463f8d5e375afadb7ae6c9be96396aa92fbcbf3198f4c1de656e8ccc9f67b606e7e5d5ccde483fb9126efa46ce7f29dc9a56d6bbc8dcb4b21eea2dc6f41ccbfb762edca6171b7c26dc990ef3e78b7f3efe2f7a26b6e9473cb24be43970e4a3328ef9e47b3d9ff2199ff3055ff2155ff34dfacf2ddff182eff901e32b7fe3c7499f567d4ada555ee3757ec9aff835bf493336f82d6ff23bde4a639b77f83def66bde5397fe03dfec8fb697ce2033ee4cf69c617aeb866958666c30db765fd8efbac9619437285e60bb2349223bfd453a038e9e9888e8b7a9f4ee894cee89c2ed28c4bbaa26bd67443b73fd6d3091fd01d2de89e1e92fe2b7d4b3e2cf58f3fd243fd44abb446eb49fd925ed16b7a431bf496368b7ee4757af737f5166d27f50ebda75d9ad307daa38fb43fe9e9131dd0217d4e3e7ea12aa96b5249adc950432d75d427f560d9d2942f6be9c98ed6d1c27a1b6c5ac71ed9e3149b3d7b92e2b249fb497dfa7d3dd8337b6e2fd2b8b45789aeed8dbdb5777661693952b3a0ff763dff6bfa3f7e5ef9138fb14e09</data> + </image> + <image name="image1" > + <data format="XPM.GZ" length="2493" >789ca59459531b391446dff9152ef4464dddb8dbbd566a1eb2af10c84a929a87de8c0dd86c76623235ff3dfa8eb0878c3309a9e850a64fe9d3b5a4967c6babb7bfbbdddbbab57131ab66e3a6d78caaf3de563b9f4c2e3ffef5e7df1b9b71dcf37f45de8b37ffd8d8dc9bf59adecec9b493d8dc8bebd3f0311e09fc151e0b7c07af05fe146f84dca9b88b1241ff17794cc347782ac89fc90791a07f8a27026ff042e043bc128c3fc51b417f8db7028ff14ee0bbc1b3a62af177f850e07bc1b3b60aeb3b90277d81bfc0a33caac37c3b9c86bfc67381b77821f00778990f9bd09fe0b5c01fe26d91b561bf2a79da17acf7088f044e7db693bc9be003c1f847c1cb7e17fad9ff341178a84f23ff12cf04fe18cfcbbc633f1dfb91760277f2ac2fc8e7782ce83fc60782fe90e70be83fc77dbbdaef27782ee83fc40b814f975e87fdb8c0ebacaec3f933bc13f878e94d582fe7271b0afc64e94da8cff9c9fdfb6dc2f9e1fbf381c039df795aa55d78df255e0abcc03b81bf97737cc378e65b1455d186f1295e099cfd28ea2a6d42bd7dbc15cc8ffb500e04fd039c463ff7b96c05fd91bc4a05fe1c2f57f7611baf57e7bf8fb702ff20e7ba87f7fb0c4f933809e7330b2ef0b7f850e097f22616cc8ffbc2750df35fe089c0efe079522661fdbc9fa62cea229c8f37782df0bbf2364eda24cc77125ce0fc3eb449e11bfe19678138e7b3ed047e4fdec5abfbc3ef5397e4691ed6c7fdeb0a817fc22b81df970fe3b44ccbf0637b737e276fce2aabadf14fad7536bc7a3ab0918dd7f376684776ec99d8d44e3ca776e69fce3d1736b3f9b7799ffe649f6de1b9f47cb13b76d7eed97dfff4c01eda237b1c4684bc3df1b5437a39e2a93db3e7b6edd9b117b66b7b9ef92affd2cf63710d8d187b5e79c6365fb2cabffe4f5e23deb09a7f797b2dff6e2d2ff6ed3dff3f58df7f46d7f2f177f3034b2cb5cc726c3d5f58e9cc3957b93a8c708d1f915c8dfe79fd856b9577ddffe44b3774076ee419933ef4335fb8237774d3fadfb09677c77ee6233771ad9b527f0427eb7977fa6bf5dd19f54757d55b774efd095c7c273ffbc5f9cffddb8e7e8cbb767e18f1537ef73ede28ffcfed8daf804d6c7a</data> + </image> + <image name="image2" > + <data format="XPM.GZ" length="1232" >789ccdd24b4fe2501c86f13d9fa2811d99a8ad9442cc2c44f082327169625c1c4e5b4f552e721398cc771f9f570907837bff0f8bfef226400287d5e0eeb617540f4bd399991536b0ce4c826a3a1f0c56f70fbfff96ca5114bcbf6a6110967f95ca07810dfe8c8619cfeefdb972a483e7306c107c84518de0293c360473312598c15a83602a1a8256b404fb30d64103eb09c10a4c9a047bb019119c8931c12e3475821dd88f094ec53ac1b5a8834bd1127c13738237d08604afc498e0b5a88313982604dba221f82a5a82633127b882594470211e137c116382976242f0496c121c8929c10b3127f80cf3238267624870282604e76293604bd4978603516f0d0b51a7ffd8dedb2c15d3b7699ae58feecb522936e7dcee62b6cb93db59fadbe5f9c5f98bdd0c03371c8d9db7a4dee770fb96e275329ded5f8af9e2eddb65f9a396cc5f566b6f392d8ad6fcf3ceda1d6f396f5d5c2e3e6ed5beea7a8b1b5fdf2c3f6edde9f6bce5c0ed9cff6b7fff3fd8b3fc3b29fd07f8c43cbd</data> + </image> + </images> +</ui> diff --git a/tools/testcon/scripts/javascript.js b/tools/testcon/scripts/javascript.js new file mode 100644 index 0000000..e2bd54b --- /dev/null +++ b/tools/testcon/scripts/javascript.js @@ -0,0 +1,25 @@ +function QAxWidget2::Click() +{ + QAxWidget2.lineWidth++; + MainWindow.logMacro(0, "Hello from JavaScript: QAxWidget2::Click", 0, ""); +} + +function fatLines() +{ + QAxWidget2.lineWidth = 25; +} + +function thinLines() +{ + QAxWidget2.lineWidth = 1; +} + +function setLineWidth(width) +{ + QAxWidget2.lineWidth = width; +} + +function getLineWidth() +{ + return(QAxWidget2.lineWidth) +} diff --git a/tools/testcon/scripts/perlscript.pl b/tools/testcon/scripts/perlscript.pl new file mode 100644 index 0000000..232ec91 --- /dev/null +++ b/tools/testcon/scripts/perlscript.pl @@ -0,0 +1,65 @@ +############################################################################# +## +## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is part of the ActiveQt module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## No Commercial Usage +## This file contains pre-release code and may not be distributed. +## You may use this file in accordance with the terms and conditions +## contained in the Technology Preview License Agreement accompanying +## this package. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## If you have questions regarding the use of this file, please contact +## Nokia at qt-info@nokia.com. +## +## +## +## +## +## +## +## +## $QT_END_LICENSE$ +## +############################################################################# + +sub QAxWidget2_Click { + $QAxWidget2->{'lineWidth'} = $QAxWidget2->{'lineWidth'} + 1; + $MainWindow->logMacro(0, "Hello from Perl: QAxWidget2_Click", 0, ""); +} + +sub fatLines +{ + $QAxWidget2->{'lineWidth'} = 25; +} + +sub thinLines +{ + $QAxWidget2->{'lineWidth'} = 1; +} + +sub setLineWidth(width) +{ + $QAxWidget2->{'lineWidth'} = width; +} + +sub getLineWidth() +{ + return $QAxWidget2->{'lineWidth'}; +} diff --git a/tools/testcon/scripts/pythonscript.py b/tools/testcon/scripts/pythonscript.py new file mode 100644 index 0000000..81aa926 --- /dev/null +++ b/tools/testcon/scripts/pythonscript.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +############################################################################# +## +## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is part of the test suite of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## No Commercial Usage +## This file contains pre-release code and may not be distributed. +## You may use this file in accordance with the terms and conditions +## contained in the Technology Preview License Agreement accompanying +## this package. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## If you have questions regarding the use of this file, please contact +## Nokia at qt-info@nokia.com. +## +## +## +## +## +## +## +## +## $QT_END_LICENSE$ +## +############################################################################# + +def QAxWidget2_Click(): + QAxWidget2.lineWidth = QAxWidget2.lineWidth + 1; + MainWindow.logMacro(0, "Hello from Python: QAxWidget2_Click", 0, ""); + +def fatLines(): + QAxWidget2.lineWidth = 25; + +def thinLines(): + QAxWidget2.lineWidth = 1; + +def setLineWidth(width): + QAxWidget2.lineWidth = width; + +def getLineWidth(): + return QAxWidget2.lineWidth; diff --git a/tools/testcon/scripts/vbscript.vbs b/tools/testcon/scripts/vbscript.vbs new file mode 100644 index 0000000..bd29f19 --- /dev/null +++ b/tools/testcon/scripts/vbscript.vbs @@ -0,0 +1,20 @@ +Sub QAxWidget2_Click + QAxWidget2.lineWidth = QAxWidget2.lineWidth + 1 + MainWindow.logMacro 0, "Hello from VBScript: QAxWidget2_Click", 0, "" +End Sub + +Sub fatLines + QAxWidget2.lineWidth = 25 +End Sub + +Sub thinLines + QAxWidget2.lineWidth = 1 +End Sub + +Sub setLineWidth(width) + QAxWidget2.lineWidth = width +End Sub + +Public Function getLineWidth + getLineWidth = QAxWidget2.lineWidth +End Function diff --git a/tools/testcon/testcon.idl b/tools/testcon/testcon.idl new file mode 100644 index 0000000..7dd88a5 --- /dev/null +++ b/tools/testcon/testcon.idl @@ -0,0 +1,44 @@ +/**************************************************************************** +** Interface definition generated for ActiveQt project +** +** 'C:\depot\qt\3.3\extensions\activeqt\tools\testcon\testcon.exe' +** +** Created: Fr 31. Okt 15:33:50 2003 +** +** WARNING! All changes made in this file will be lost! +****************************************************************************/ + +import "ocidl.idl"; +#include <olectl.h> + +[ + uuid(4A43E44D-9D1D-47E5-A1E5-58FE6F7BE0A4), + version(1.0), + helpstring("testcon 1.0 Type Library") +] +library testconLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(3FC86F5F-8B15-4428-8F6B-482BAE91F1AE), + helpstring("MainWindow Interface") + ] + dispinterface IMainWindow + { + properties: + methods: + [id(7)] void logMacro( [in] int p_code, [in] BSTR p_description, [in] int p_sourcePosition, [in] BSTR p_sourceText); + }; + + [ + aggregatable, + helpstring("MainWindow Class"), + uuid(5F5CE700-48A8-47B1-9B06-3B7F79E41D7C) + ] + coclass MainWindow + { + [default] dispinterface IMainWindow; + }; +}; diff --git a/tools/testcon/testcon.pro b/tools/testcon/testcon.pro new file mode 100644 index 0000000..89f8067 --- /dev/null +++ b/tools/testcon/testcon.pro @@ -0,0 +1,21 @@ +TEMPLATE = app + +CONFIG += qaxserver qaxserver_no_postlink qaxcontainer +# QT += qt3support + +# ui_qaxselect.h +INCLUDEPATH += $$QT_SOURCE_TREE/tools/activeqt/container/debug \ + $$QT_SOURCE_TREE/tools/activeqt/container/release \ + $$QT_BUILD_TREE/src/activeqt/container \ + +SOURCES = main.cpp docuwindow.cpp mainwindow.cpp invokemethod.cpp changeproperties.cpp ambientproperties.cpp controlinfo.cpp +HEADERS = docuwindow.h mainwindow.h invokemethod.h changeproperties.h ambientproperties.h controlinfo.h +FORMS = mainwindow.ui invokemethod.ui changeproperties.ui ambientproperties.ui controlinfo.ui +RC_FILE = testcon.rc + +win32-borland { + QMAKE_POST_LINK = -midl $$QT_SOURCE_TREE/tools/activeqt/testcon/testcon.idl +} else { + !win32-g++*:QMAKE_POST_LINK = midl $$QT_SOURCE_TREE/tools/activeqt/testcon/testcon.idl && move testcon.tlb $(TARGETDIR) + +} diff --git a/tools/testcon/testcon.rc b/tools/testcon/testcon.rc new file mode 100644 index 0000000..f17bd26 --- /dev/null +++ b/tools/testcon/testcon.rc @@ -0,0 +1,35 @@ +#ifndef Q_CC_BOR +#include <winver.h> +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 3, 2, 0, 0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)\0" + VALUE "FileDescription", "ActiveQt Test Container\0" + VALUE "FileVersion", "1,0,0,1\0" + VALUE "InternalName", "testcon\0" + VALUE "LegalCopyright", "Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "testcon.exe\0" + VALUE "ProductName", "ActiveQt Test Container\0" + VALUE "ProductVersion", "3, 2, 0, 0\0" + END + END + END +/* End of Version info */ + diff --git a/tools/tools.pro b/tools/tools.pro new file mode 100644 index 0000000..c50010c --- /dev/null +++ b/tools/tools.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs + +CONFIG += ordered + +SUBDIRS = dumpdoc \ + dumpcpp \ + testcon + |