summaryrefslogtreecommitdiffstats
path: root/doc/src/examples/activeqt/dotnet.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/src/examples/activeqt/dotnet.qdoc')
-rw-r--r--doc/src/examples/activeqt/dotnet.qdoc355
1 files changed, 355 insertions, 0 deletions
diff --git a/doc/src/examples/activeqt/dotnet.qdoc b/doc/src/examples/activeqt/dotnet.qdoc
new file mode 100644
index 0000000..afe7034
--- /dev/null
+++ b/doc/src/examples/activeqt/dotnet.qdoc
@@ -0,0 +1,355 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the documentation 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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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://qtsoftware.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}
+*/