summaryrefslogtreecommitdiffstats
path: root/src/activeqt/doc/src/examples/dotnet.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/activeqt/doc/src/examples/dotnet.qdoc')
-rw-r--r--src/activeqt/doc/src/examples/dotnet.qdoc308
1 files changed, 0 insertions, 308 deletions
diff --git a/src/activeqt/doc/src/examples/dotnet.qdoc b/src/activeqt/doc/src/examples/dotnet.qdoc
deleted file mode 100644
index 7f4451d..0000000
--- a/src/activeqt/doc/src/examples/dotnet.qdoc
+++ /dev/null
@@ -1,308 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \page activeqt-dotnet.html
- \title Dot Net Example (ActiveQt)
-
- \brief 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.
-
- 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.
-
- \b{Remark:} You will notice that in the generated code the following line is
- commented out:
-
- \snippet 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 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 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 activeqt/dotnet/wrapper/lib/tools.cpp 0
- \codeline
- \snippet 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 activeqt/dotnet/wrapper/lib/networker.cpp 0
- \codeline
- \snippet 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 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 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 activeqt/dotnet/wrapper/main.cs 0
- \snippet activeqt/dotnet/wrapper/main.cs 1
- \snippet activeqt/dotnet/wrapper/main.cs 2
- \snippet 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 \l {QWidget}s 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 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 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.
-
- When using the "IJW" method, in principle 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.
-*/