summaryrefslogtreecommitdiffstats
path: root/doc/html/activeqt-dotnet.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/html/activeqt-dotnet.html')
-rw-r--r--doc/html/activeqt-dotnet.html459
1 files changed, 459 insertions, 0 deletions
diff --git a/doc/html/activeqt-dotnet.html b/doc/html/activeqt-dotnet.html
new file mode 100644
index 0000000..37a7563
--- /dev/null
+++ b/doc/html/activeqt-dotnet.html
@@ -0,0 +1,459 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/extensions/activeqt/examples/dotnet/dotnet.doc:1 -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>Walkthrough: Using Qt objects in Microsoft .NET</title>
+<style type="text/css"><!--
+fn { margin-left: 1cm; text-indent: -1cm; }
+a:link { color: #004faf; text-decoration: none }
+a:visited { color: #672967; text-decoration: none }
+body { background: #ffffff; color: black; }
+--></style>
+</head>
+<body>
+
+<table border="0" cellpadding="0" cellspacing="0" width="100%">
+<tr bgcolor="#E5E5E5">
+<td valign=center>
+ <a href="index.html">
+<font color="#004faf">Home</font></a>
+ | <a href="classes.html">
+<font color="#004faf">All&nbsp;Classes</font></a>
+ | <a href="mainclasses.html">
+<font color="#004faf">Main&nbsp;Classes</font></a>
+ | <a href="annotated.html">
+<font color="#004faf">Annotated</font></a>
+ | <a href="groups.html">
+<font color="#004faf">Grouped&nbsp;Classes</font></a>
+ | <a href="functions.html">
+<font color="#004faf">Functions</font></a>
+</td>
+<td align="right" valign="center"><img src="logo32.png" align="right" width="64" height="32" border="0"></td></tr></table><h1 align=center>Walkthrough: Using Qt objects in Microsoft .NET</h1>
+
+
+
+
+<!-- toc -->
+<ul>
+<li><a href="#1"> Introduction
+</a>
+<ul>
+<li><a href="#1-1"> Qt vs .NET
+</a>
+</ul>
+<li><a href="#2"> Walkthrough: .NET interop with MC++ and IJW
+</a>
+<li><a href="#3"> Walkthrough: .NET/COM Interop with ActiveQt
+</a>
+<ul>
+<li><a href="#3-1"> Starting a Project
+</a>
+<li><a href="#3-2"> Importing Qt Widgets
+</a>
+<li><a href="#3-3"> Using Qt Widgets
+</a>
+<li><a href="#3-4"> Handling Qt Signals
+</a>
+</ul>
+<li><a href="#4"> Summary
+</a>
+<ul>
+<li><a href="#4-1"> Limitations
+</a>
+<li><a href="#4-2"> Performance Considerations
+</a>
+</ul>
+</ul>
+<!-- endtoc -->
+
+<p> <h2> Introduction
+</h2>
+<a name="1"></a><p> In the following walkthrough we will show how Qt objects can be used
+in a .NET environment, and how .NET objects can be used in a Qt
+environment.
+<p> <h3> Qt vs .NET
+</h3>
+<a name="1-1"></a><p> Qt is a C++ library and is compiled into traditional, native
+binaries that make full use of the performance provided by the
+runtime environment.
+<p> 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 <em>Common Language Runtime</em> (CLR).
+<p> Another key concept is that of <em>managed code</em>. 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.
+<p> The MS compilers for C# and VB.NET will only produce managed
+code. Such programs cannot directly call normal, native functions
+or classes. <a href="#footnote1"><sup>(1)</sup></a><a name="footnote-call1"></a>
+<p> 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 <tt>__gc</tt> 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.
+<p> 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 <a href="activeqt.html#ActiveQt">ActiveQt</a> 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.
+<p> The impatient reader, who right away wants to see a <a href="qpushbutton.html">QPushButton</a> and a
+custom Qt widget (<a href="qaxserver-example-multiple.html">QAxWidget2</a>) 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 <tt>examples/dotnet/walkthrough/csharp.csproj</tt>,
+<tt>examples/dotnet/walkthrough/vb.vbproj</tt>
+<a href="#footnote2"><sup>(2)</sup></a><a name="footnote-call2"></a>
+or <tt>examples/dotnet/wrapper/wrapper.sln</tt> into the IDE and run
+the solution.
+<p> <h2> Walkthrough: .NET interop with MC++ and IJW
+</h2>
+<a name="2"></a><p> 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.
+<p>
+
+<pre> // native Qt/C++ class
+ class Worker : public <a href="qobject.html">QObject</a>
+ {
+ <a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
+ Q_PROPERTY(QString statusString READ statusString WRITE setStatusString)
+ public:
+ Worker();
+
+ <a href="qstring.html">QString</a> statusString() const;
+
+ public slots:
+ void setStatusString(const <a href="qstring.html">QString</a> &amp;string);
+
+ signals:
+ void statusStringChanged(const <a href="qstring.html">QString</a> &amp;string);
+
+ private:
+ <a href="qstring.html">QString</a> status;
+ };
+</pre>
+<p> The Qt class has nothing unusual for Qt users, and as even the Qt
+specialities like <tt>Q_PROPERTY</tt>, <tt>slots</tt> and <tt>signals</tt> are
+implemented with straight C++ they don't cause any trouble when
+compiling this class with any C++ compiler.
+<p>
+
+<pre> 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;
+ };
+</pre>
+<p> The .NET wrapper class uses keywords that are part of MC++ to indicate
+that the class is managed/garbage collected (<tt>__gc</tt>), and that <tt>StatusString</tt> should be accessible as a property in languages that
+support this concept (<tt>__property</tt>). We also declare an event
+function <tt>statusStringChanged(String*)</tt> (<tt>__event</tt>), the
+equivalent of the respective signal in the Qt class.
+<p> 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. <a href="qstring.html">QString</a> objects need to be converted into objects
+of type <tt>String*</tt>.
+<p> 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 <a href="#footnote3"><sup>(3)</sup></a><a name="footnote-call3"></a> 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.
+<p> However, two methods are provided that solves this problem easily. The
+first is to use a <em>pinned</em> pointer, i.e. declare the pointer variable
+with the <tt>__pin</tt> 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 <tt>gcroot</tt> smartpointer
+template type. This lets you create safe pointers to managed
+objects. E.g. a variable of type <tt>gcroot&lt;String&gt;</tt> 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.
+<p>
+
+<pre> #include &lt;<a href="qstring-h.html">qstring.h</a>&gt;
+
+ #using &lt;mscorlib.dll&gt;
+ #include &lt;vcclr.h&gt;
+
+ using namespace System;
+
+ String *QStringToString(const <a href="qstring.html">QString</a> &amp;qstring)
+ {
+ <a name="x2467"></a> return new String(qstring.<a href="qstring.html#ucs2">ucs2</a>());
+ }
+</pre>
+<p> <pre> QString StringToQString(String *string)
+ {
+ wchar_t __pin *chars = PtrToStringChars(string);
+ return QString::fromUcs2(chars);
+ }
+</pre>
+<p> The convertor functions can then be used in the wrapper class
+implementation to call the functions in the native C++ class.
+<p>
+
+<pre> #include "networker.h"
+ #include "worker.h"
+ #include "tools.h"
+
+ netWorker::netWorker()
+ {
+ workerObject = new Worker();
+ }
+</pre>
+<p> <pre> netWorker::~netWorker()
+ {
+ delete workerObject;
+ }
+</pre>
+<p> The constructor and destructor simply create and destroy the Qt
+object wrapped using the C++ operators <tt>new</tt> and <tt>delete</tt>.
+<p> <pre> String *netWorker::get_StatusString()
+ {
+ return QStringToString(workerObject-&gt;statusString());
+ }
+</pre>
+<p> 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.
+<p> <pre> void netWorker::set_StatusString(String *string)
+ {
+ workerObject-&gt;setStatusString(StringToQString(string));
+ __raise statusStringChanged(string);
+ }
+</pre>
+<p> The property setter calls the native Qt class before firing the
+event using the <tt>__raise</tt> keyword.
+<p> 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.
+<p>
+
+<pre> 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]
+ static void Main(string[] args)
+ {
+ App app = new App();
+ app.Run();
+ }
+ }
+ }
+</pre>
+<p> <h2> Walkthrough: .NET/COM Interop with ActiveQt
+</h2>
+<a name="3"></a><p> Fortunately .NET provides a generic wrapper for COM objects, the
+<em>Runtime Callable Wrapper</em> (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.
+<p> Making a <a href="qobject.html">QObject</a> class into a COM object is easily achieved with
+ActiveQt and demonstrated in the <a href="qaxserver-examples.html">examples</a>. 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 <a href="qaxserver-demo-multiple.html">demonstration pages</a> in Internet
+Explorer to verify that the controls are functional.
+<p> <h3> Starting a Project
+</h3>
+<a name="3-1"></a><p> 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".
+<p> <h3> Importing Qt Widgets
+</h3>
+<a name="3-2"></a><p> 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".
+<p> 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 <a href="#footnote4"><sup>(4)</sup></a><a name="footnote-call4"></a> .
+<p> <h3> Using Qt Widgets
+</h3>
+<a name="3-3"></a><p> We can now add an instance of QAxWidget2 and a <a href="qpushbutton.html">QPushButton</a> 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.
+<p> In the property editor of Visual Studio we can modify the properties
+of our controls - QPushButton exposes the <a href="qwidget.html">QWidget</a> 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".
+<p> We can also change the Qt properties, e.g. set the "text" property
+of the <tt>resetButton</tt> to "Reset", and the "lineWidth" property of the
+<tt>circleWidget</tt> 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 <tt>circleWidget</tt> to "Left, Top, Right, Bottom", and
+the anchors of the <tt>resetButton</tt> to "Bottom, Right".
+<p> 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.
+<p> <h3> Handling Qt Signals
+</h3>
+<a name="3-4"></a><p> We will now implement event handlers for the widgets. Select the
+<tt>circleWidget</tt> 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 <tt>circleClicked</tt> for the <tt>ClickEvent</tt> to increase
+the line width by one for every click:
+<p>
+
+<pre> private void circleClicked(object sender, System.EventArgs e)
+ {
+ this.circleWidget.lineWidth++;
+ }
+</pre>
+<p> 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.
+<p> We will also implement an event handler for the <tt>clicked</tt> signal
+emitted by <a href="qpushbutton.html">QPushButton</a>. Add the event handler <tt>resetLineWidth</tt> to
+the <tt>clicked</tt> event, and implement the generated function:
+<p> <pre> private void resetLineWidth(object sender, System.EventArgs e)
+ {
+ this.circleWidget.lineWidth = 1;
+ this.resetButton.setFocus();
+ }
+</pre>
+<p> We reset the property to 1, and also call the <tt>setFocus()</tt> 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).
+<p> 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.
+<p> <h2> Summary
+</h2>
+<a name="4"></a><p> 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 <a href="qaxfactory.html">QAxFactory</a> implementation in the otherwise completely
+cross-platform Qt project provides the glue that .NET needs to to
+generate the RCW.
+<p> If this is not sufficient we can implement our own wrapper classes
+thanks to the C++ extensions provided by Microsoft.
+<p> <h3> Limitations
+</h3>
+<a name="4-1"></a><p> 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 <a href="qobject.html">QObject</a> and <a href="qwidget.html">QWidget</a> 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 <a href="http://www.trolltech.com/products/qsa">QSA</a>, the cross platform
+scripting solution for Qt applications, and to COM clients in general.
+<p> When using the "IJW" method, in priciple the only limitation is the
+time required to write the wrapper classes and data type conversion
+functions.
+<p> <h3> Performance Considerations
+</h3>
+<a name="4-2"></a><p> 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.
+<p> 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.
+<p>
+<hr>
+<ol> <li><a name="footnote1"></a>
+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. <a href="#footnote-call1">Back...</a> <li><a name="footnote2"></a>
+
+You will notice that in the generated code the following line is
+commented out: <pre>
+ ' VB is case insensitive, but our C++ controls are not.
+ ' Me.resetButton.enabled = True
+ </pre>
+
+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.
+ <a href="#footnote-call2">Back...</a> <li><a name="footnote3"></a>
+Indeed, the compiler will in
+many cases disallow it. <a href="#footnote-call3">Back...</a> <li><a name="footnote4"></a>
+Icons could be added by modifying the
+way the controls register themselves. <a href="#footnote-call4">Back...</a></ol>
+</hr><p>See also <a href="qaxserver-examples.html">The QAxServer Examples</a>.
+
+<!-- eof -->
+<p><address><hr><div align=center>
+<table width=100% cellspacing=0 border=0><tr>
+<td>Copyright &copy; 2007
+<a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
+<td align=right><div align=right>Qt 3.3.8</div>
+</table></div></address></body>
+</html>