doc/src/examples/activeqt/dotnet.qdoc
branchRCL_3
changeset 7 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 7:3f74d0d4af4c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the documentation of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \page activeqt-dotnet.html
       
    44     \title Dot Net Example (ActiveQt)
       
    45 
       
    46     The Dot Net example demonstrates how Qt objects can be used in a
       
    47     .NET environment, and how .NET objects can be used in a Qt
       
    48     environment.
       
    49 
       
    50     If you need to combine Qt and Win Forms widgets in the same
       
    51     application, you might want to use the higher-level
       
    52     \l{QtWinForms Solution} instead.
       
    53 
       
    54     Contents:
       
    55 
       
    56     \tableofcontents
       
    57 
       
    58     \section1 Qt vs. .NET
       
    59 
       
    60     Qt is a C++ library and is compiled into traditional, native
       
    61     binaries that make full use of the performance provided by the
       
    62     runtime environment.
       
    63 
       
    64     One of the key concepts of .NET is the idea of "intermediate language
       
    65     code" - the source code is compiled into a bytecode format, and at
       
    66     runtime, that bytecode is executed in a virtual machine - the \e
       
    67     {Common Language Runtime} (CLR).
       
    68 
       
    69     Another key concept is that of \e {managed code}. This is essentially
       
    70     intermediate language code written in such a way that the CLR can take
       
    71     care of the memory management, i.e. the CLR will do automatic garbage
       
    72     collection, so the application code does not need to explicitly free
       
    73     the memory for unused objects.
       
    74 
       
    75     The MS compilers for C# and VB.NET will only produce managed
       
    76     code. Such programs cannot directly call normal, native functions
       
    77     or classes. \footnote The .NET framework provides Platform Invocation
       
    78     Services - P/Invoke - that enable managed code to call native C (not
       
    79     C++) functions located in DLLs directly. The resulting application
       
    80     then becomes partially unmanaged.\endfootnote
       
    81 
       
    82     The MS C++ compiler for .NET on the other hand, can produce both
       
    83     normal and managed code. To write a C++ class that can be compiled
       
    84     into managed code, the developer must flag the class as managed using
       
    85     the \c __gc keyword, and restrict the code to only use the subset of
       
    86     C++ known as "Managed Extensions for C++", or MC++ for short. The
       
    87     advantage is that MC++ code can freely call and use normal C++
       
    88     functions and classes. And it also works the other way around: normal
       
    89     C++ code can call managed functions and use managed classes (e.g. the
       
    90     entire .NET framework class library), including managed functions and
       
    91     classes implemented in C# or VB.NET. This feature of mixing managed
       
    92     and normal C++ code immensely eases the interoperability with .NET,
       
    93     and is by Microsoft referred to as the "It Just Works" (IJW) feature.
       
    94 
       
    95     This document demonstrates two different ways of integrating normal
       
    96     C++ code (that uses Qt) with managed .NET code. First, the manual way
       
    97     is presented, which includes using a thin MC++ wrapper class around
       
    98     the normal Qt/C++ class. Then, the automated way is presented, which
       
    99     utilizes the ActiveQt framework as a generic bridge. The advantage of
       
   100     the first method is that it gives the application developer full
       
   101     control, while the second method requires less coding and relieves the
       
   102     developer of dealing with the conversion between managed and normal
       
   103     data objects.
       
   104 
       
   105     The impatient reader, who right away wants to see a QPushButton
       
   106     and a custom Qt widget (\l{activeqt/multiple}{QAxWidget2}) run in
       
   107     a .NET GUI application is referred to the example directory of
       
   108     ActiveQt. It contains the result of this walkthrough using both
       
   109     C# and VB.NET, created with Visual Studio .NET (not 2003).
       
   110     Load \c {examples/dotnet/walkthrough/csharp.csproj},
       
   111     \c {examples/dotnet/walkthrough/vb.vbproj}
       
   112     or \c {examples/dotnet/wrapper/wrapper.sln} into the IDE and run
       
   113     the solution.
       
   114 
       
   115     \bold{Remark:} You will notice that in the generated code the following line is
       
   116     commented out:
       
   117 
       
   118     \snippet doc/src/snippets/code/doc_src_examples_activeqt_dotnet.qdoc 0
       
   119 
       
   120     This line is regenerated without comment whenever you change the
       
   121     dialog, in which case you have to comment it out again to be able
       
   122     to run the project. This is a bug in the original version of
       
   123     Visual Studio.NET, and is fixed in the 2003 edition.
       
   124 
       
   125     \section1 Walkthrough: .NET interop with MC++ and IJW
       
   126 
       
   127     Normal C++ classes and functions can be used from managed .NET code by
       
   128     providing thin wrapper classes written in MC++. The wrapper class will
       
   129     take care of forwarding the calls to the normal C++ functions or
       
   130     methods, and converting parameter data as necessary. Since the wrapper
       
   131     class is a managed class, it can be used without further ado in any
       
   132     managed .NET application, whether written in C#, VB.NET, MC++ or other
       
   133     managed programming language.
       
   134 
       
   135     \snippet examples/activeqt/dotnet/wrapper/lib/worker.h 0
       
   136 
       
   137     The Qt class has nothing unusual for Qt users, and as even the Qt
       
   138     specialities like \c Q_PROPERTY, \c slots and \c signals are
       
   139     implemented with straight C++ they don't cause any trouble when
       
   140     compiling this class with any C++ compiler.
       
   141 
       
   142     \snippet examples/activeqt/dotnet/wrapper/lib/networker.h 0
       
   143 
       
   144     The .NET wrapper class uses keywords that are part of MC++ to indicate
       
   145     that the class is managed/garbage collected (\c {__gc}), and that \c
       
   146     StatusString should be accessible as a property in languages that
       
   147     support this concept (\c {__property}).  We also declare an event
       
   148     function \c statusStringChanged(String*) (\c {__event}), the
       
   149     equivalent of the respective signal in the Qt class.
       
   150 
       
   151     Before we can start implementing the wrapper class we need a way to
       
   152     convert Qt's datatypes (and potentionally your own) into .NET
       
   153     datatypes, e.g. \c QString objects need to be converted into objects
       
   154     of type \c {String*}.
       
   155 
       
   156     When operating on managed objects in normal C++ code, a little extra
       
   157     care must be taken because of the CLR's garbage collection. A normal
       
   158     pointer variable should not \footnote Indeed, the compiler will in
       
   159     many cases disallow it. \endfootnote be used to refer to a managed
       
   160     object. The reason is that the garbage collection can kick in at any
       
   161     time and move the object to another place on the heap, leaving you
       
   162     with an invalid pointer.
       
   163 
       
   164     However, two methods are provided that solves this problem easily. The
       
   165     first is to use a \e pinned pointer, i.e. declare the pointer variable
       
   166     with the \c __pin keyword. This guarantees that the object pointed to
       
   167     will not be moved by the garbage collector. It is recommended that
       
   168     this method not be used to keep a references to managed objects for a
       
   169     long time, since it will decrease the efficiency of the garbage
       
   170     collector. The second way is to use the \c gcroot smartpointer
       
   171     template type. This lets you create safe pointers to managed
       
   172     objects. E.g. a variable of type \c gcroot<String> will always point
       
   173     to the String object, even if it has been moved by the garbage
       
   174     collector, and it can be used just like a normal pointer.
       
   175 
       
   176     \snippet examples/activeqt/dotnet/wrapper/lib/tools.cpp 0
       
   177     \codeline
       
   178     \snippet examples/activeqt/dotnet/wrapper/lib/tools.cpp 1
       
   179 
       
   180     The convertor functions can then be used in the wrapper class
       
   181     implementation to call the functions in the native C++ class.
       
   182 
       
   183     \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 0
       
   184     \codeline
       
   185     \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 1
       
   186 
       
   187     The constructor and destructor simply create and destroy the Qt
       
   188     object wrapped using the C++ operators \c new and \c delete.
       
   189 
       
   190     \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 2
       
   191 
       
   192     The netWorker class delegates calls from the .NET code to the native
       
   193     code. Although the transition between those two worlds implies a small
       
   194     performance hit for each function call, and for the type conversion,
       
   195     this should be negligible since we are anyway going to run within the
       
   196     CLR.
       
   197 
       
   198     \snippet examples/activeqt/dotnet/wrapper/lib/networker.cpp 3
       
   199 
       
   200     The property setter calls the native Qt class before firing the
       
   201     event using the \c __raise keyword.
       
   202 
       
   203     This wrapper class can now be used in .NET code, e.g. using C++, C#,
       
   204     Visual Basic or any other programming language available for .NET.
       
   205 
       
   206     \snippet examples/activeqt/dotnet/wrapper/main.cs 0
       
   207     \snippet examples/activeqt/dotnet/wrapper/main.cs 1
       
   208     \snippet examples/activeqt/dotnet/wrapper/main.cs 2
       
   209     \snippet examples/activeqt/dotnet/wrapper/main.cs 3
       
   210 
       
   211     \section1 Walkthrough: .NET/COM Interop with ActiveQt
       
   212 
       
   213     Fortunately .NET provides a generic wrapper for COM objects, the
       
   214     \e {Runtime Callable Wrapper} (RCW). This RCW is a proxy for the
       
   215     COM object and is generated by the CLR when a .NET Framework client
       
   216     activates a COM object. This provides a generic way to reuse COM
       
   217     objects in a .NET Framework project.
       
   218 
       
   219     Making a QObject class into a COM object is easily achieved with
       
   220     ActiveQt and demonstrated in the QAxServer examples (e.g., the
       
   221     \l{activeqt/simple}{Simple} example). The walkthrough will use
       
   222     the Qt classes implemented in those examples, so the first thing
       
   223     to do is to make sure that those  examples have been built
       
   224     correctly, e.g. by opening the
       
   225     \l{qaxserver-demo-multiple.html}{demonstration pages} in Internet
       
   226     Explorer to verify that the controls are functional.
       
   227 
       
   228     \section2 Starting a Project
       
   229 
       
   230     Start Visual Studio.NET, and create a new C# project for writing a
       
   231     Windows application. This will present you with an empty form in
       
   232     Visual Studio's dialog editor. You should see the toolbox, which
       
   233     presents you with a number of available controls and objects in
       
   234     different categories. If you right-click on the toolbox it allows
       
   235     you to add new tabs. We will add the tab "Qt".
       
   236 
       
   237     \section2 Importing Qt Widgets
       
   238 
       
   239     The category only has a pointer tool by default, and we have to add
       
   240     the Qt objects we want to use in our form. Right-click on the empty
       
   241     space, and select "Customize". This opens a dialog that has two
       
   242     tabs, "COM Components" and ".NET Framework Components". We used
       
   243     ActiveQt to wrap QWidgets into COM objects, so we select the "COM
       
   244     Components" page, and look for the classes we want to use, e.g.
       
   245     "QPushButton" and "QAxWidget2".
       
   246 
       
   247     When we select those widgets and close the dialog the two widgets
       
   248     will now be available from the toolbox as grey squares with their
       
   249     name next to it \footnote Icons could be added by modifying the
       
   250     way the controls register themselves. \endfootnote.
       
   251 
       
   252     \section2 Using Qt Widgets
       
   253 
       
   254     We can now add an instance of QAxWidget2 and a QPushButton to
       
   255     the form. Visual Studio will automatically generate the RCW for the
       
   256     object servers. The QAxWidget2 instance takes most of the upper
       
   257     part of the form, with the QPushButton in the lower right corner.
       
   258 
       
   259     In the property editor of Visual Studio we can modify the properties
       
   260     of our controls - QPushButton exposes the \c QWidget API and has many
       
   261     properties, while QAxWidget2 has only the Visual Studio standard
       
   262     properties in addition to its own property "lineWidth" in the
       
   263     "Miscellaneous" category. The objects are named "axQPushButton1" and
       
   264     "axQAxWidget21", and since especially the last name is a bit
       
   265     confusing we rename the objects to "resetButton" and "circleWidget".
       
   266 
       
   267     We can also change the Qt properties, e.g. set the "text" property
       
   268     of the \c resetButton to "Reset", and the "lineWidth" property of the
       
   269     \c circleWidget to 5. We can also put those objects into the layout
       
   270     system that Visual Studio's dialog editor provides, e.g. by setting
       
   271     the anchors of the \c circleWidget to "Left, Top, Right, Bottom", and
       
   272     the anchors of the \c resetButton to "Bottom, Right".
       
   273 
       
   274     Now we can compile and start the project, which will open a user
       
   275     interface with our two Qt widgets. If we can resize the dialog,
       
   276     the widgets will resize appropriately.
       
   277 
       
   278     \section2 Handling Qt Signals
       
   279 
       
   280     We will now implement event handlers for the widgets. Select the
       
   281     \c circleWidget and select the "Events" page in the property
       
   282     editor. The widget exposes events because the QAxWidget2 class has
       
   283     the "StockEvents" attribute set in its class definition. We implement
       
   284     the event handler \c circleClicked for the \c ClickEvent to increase
       
   285     the line width by one for every click:
       
   286 
       
   287     \snippet examples/activeqt/dotnet/walkthrough/Form1.cs 0
       
   288 
       
   289     In general we can implement a default event handler by double
       
   290     clicking on the widget in the form, but the default events for
       
   291     our widgets are right now not defined.
       
   292 
       
   293     We will also implement an event handler for the \c clicked signal
       
   294     emitted by QPushButton. Add the event handler \c resetLineWidth to
       
   295     the \c clicked event, and implement the generated function:
       
   296 
       
   297     \snippet examples/activeqt/dotnet/walkthrough/Form1.cs 1
       
   298 
       
   299     We reset the property to 1, and also call the \c setFocus() slot
       
   300     to simulate the user style on Windows, where a button grabs focus
       
   301     when you click it (so that you can click it again with the spacebar).
       
   302 
       
   303     If we now compile and run the project we can click on the circle
       
   304     widget to increase its line width, and press the reset button to
       
   305     set the line width back to 1.
       
   306 
       
   307     \section1 Summary
       
   308 
       
   309     Using ActiveQt as a universal interoperability bridge between the
       
   310     .NET world and the native world of Qt is very easy, and makes it
       
   311     often  unnecessary to implement a lot of handwritten wrapper classes.
       
   312     Instead, the QAxFactory implementation in the otherwise completely
       
   313     cross-platform Qt project provides the glue that .NET needs to to
       
   314     generate the RCW.
       
   315 
       
   316     If this is not sufficient we can implement our own wrapper classes
       
   317     thanks to the C++ extensions provided by Microsoft.
       
   318 
       
   319     \section2 Limitations
       
   320 
       
   321     All the limitations when using ActiveQt are implied when using this
       
   322     technique to interoperate with .NET, e.g. the datatypes we can use
       
   323     in the APIs can only be those supported by ActiveQt and COM. However,
       
   324     since this includes subclasses of QObject and QWidget we can wrap
       
   325     any of our datatypes into a QObject subclass to make its API
       
   326     available to .NET. This has the positive side effect that the same
       
   327     API is automatically available in
       
   328     \l{http://qt.nokia.com/products/qsa/}{QSA}, the cross platform
       
   329     scripting solution for Qt applications, and to COM clients in general.
       
   330 
       
   331     When using the "IJW" method, in priciple the only limitation is the
       
   332     time required to write the wrapper classes and data type conversion
       
   333     functions.
       
   334 
       
   335     \section2 Performance Considerations
       
   336 
       
   337     Every call from CLR bytecode to native code implies a small
       
   338     performance hit, and necessary type conversions introduce an
       
   339     additional delay with every layer that exists between the two
       
   340     frameworks. Consequently every approach to mix .NET and native
       
   341     code should try to minimize the communication necessary between
       
   342     the different worlds.
       
   343 
       
   344     As ActiveQt introduces three layers at once - the RCW, COM and finally
       
   345     ActiveQt itself - the performance penalty when using the generic
       
   346     Qt/ActiveQt/COM/RCW/.NET bridge is larger than when using a
       
   347     hand-crafted IJW-wrapper class. The execution speed however is still
       
   348     sufficient for connecting to and modifying interactive elements in a
       
   349     user interface, and as soon as the benefit of using Qt and C++ to
       
   350     implement and compile performance critical algorithms into native code
       
   351     kicks in, ActiveQt becomes a valid choice for making even non-visual
       
   352     parts of your application accessible to .NET.
       
   353 
       
   354     \sa {QtWinForms Solution}
       
   355 */