[190] | 1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
---|
| 2 | <!-- /home/espenr/tmp/qt-3.3.8-espenr-2499/qt-x11-free-3.3.8/extensions/activeqt/examples/dotnet/dotnet.doc:1 -->
|
---|
| 3 | <html>
|
---|
| 4 | <head>
|
---|
| 5 | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
---|
| 6 | <title>Walkthrough: Using Qt objects in Microsoft .NET</title>
|
---|
| 7 | <style type="text/css"><!--
|
---|
| 8 | fn { margin-left: 1cm; text-indent: -1cm; }
|
---|
| 9 | a:link { color: #004faf; text-decoration: none }
|
---|
| 10 | a:visited { color: #672967; text-decoration: none }
|
---|
| 11 | body { background: #ffffff; color: black; }
|
---|
| 12 | --></style>
|
---|
| 13 | </head>
|
---|
| 14 | <body>
|
---|
| 15 |
|
---|
| 16 | <table border="0" cellpadding="0" cellspacing="0" width="100%">
|
---|
| 17 | <tr bgcolor="#E5E5E5">
|
---|
| 18 | <td valign=center>
|
---|
| 19 | <a href="index.html">
|
---|
| 20 | <font color="#004faf">Home</font></a>
|
---|
| 21 | | <a href="classes.html">
|
---|
| 22 | <font color="#004faf">All Classes</font></a>
|
---|
| 23 | | <a href="mainclasses.html">
|
---|
| 24 | <font color="#004faf">Main Classes</font></a>
|
---|
| 25 | | <a href="annotated.html">
|
---|
| 26 | <font color="#004faf">Annotated</font></a>
|
---|
| 27 | | <a href="groups.html">
|
---|
| 28 | <font color="#004faf">Grouped Classes</font></a>
|
---|
| 29 | | <a href="functions.html">
|
---|
| 30 | <font color="#004faf">Functions</font></a>
|
---|
| 31 | </td>
|
---|
| 32 | <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>
|
---|
| 33 |
|
---|
| 34 |
|
---|
| 35 |
|
---|
| 36 |
|
---|
| 37 | <!-- toc -->
|
---|
| 38 | <ul>
|
---|
| 39 | <li><a href="#1"> Introduction
|
---|
| 40 | </a>
|
---|
| 41 | <ul>
|
---|
| 42 | <li><a href="#1-1"> Qt vs .NET
|
---|
| 43 | </a>
|
---|
| 44 | </ul>
|
---|
| 45 | <li><a href="#2"> Walkthrough: .NET interop with MC++ and IJW
|
---|
| 46 | </a>
|
---|
| 47 | <li><a href="#3"> Walkthrough: .NET/COM Interop with ActiveQt
|
---|
| 48 | </a>
|
---|
| 49 | <ul>
|
---|
| 50 | <li><a href="#3-1"> Starting a Project
|
---|
| 51 | </a>
|
---|
| 52 | <li><a href="#3-2"> Importing Qt Widgets
|
---|
| 53 | </a>
|
---|
| 54 | <li><a href="#3-3"> Using Qt Widgets
|
---|
| 55 | </a>
|
---|
| 56 | <li><a href="#3-4"> Handling Qt Signals
|
---|
| 57 | </a>
|
---|
| 58 | </ul>
|
---|
| 59 | <li><a href="#4"> Summary
|
---|
| 60 | </a>
|
---|
| 61 | <ul>
|
---|
| 62 | <li><a href="#4-1"> Limitations
|
---|
| 63 | </a>
|
---|
| 64 | <li><a href="#4-2"> Performance Considerations
|
---|
| 65 | </a>
|
---|
| 66 | </ul>
|
---|
| 67 | </ul>
|
---|
| 68 | <!-- endtoc -->
|
---|
| 69 |
|
---|
| 70 | <p> <h2> Introduction
|
---|
| 71 | </h2>
|
---|
| 72 | <a name="1"></a><p> In the following walkthrough we will show how Qt objects can be used
|
---|
| 73 | in a .NET environment, and how .NET objects can be used in a Qt
|
---|
| 74 | environment.
|
---|
| 75 | <p> <h3> Qt vs .NET
|
---|
| 76 | </h3>
|
---|
| 77 | <a name="1-1"></a><p> Qt is a C++ library and is compiled into traditional, native
|
---|
| 78 | binaries that make full use of the performance provided by the
|
---|
| 79 | runtime environment.
|
---|
| 80 | <p> One of the key concepts of .NET is the idea of "intermediate language
|
---|
| 81 | code" - the source code is compiled into a bytecode format, and at
|
---|
| 82 | runtime, that bytecode is executed in a virtual machine - the <em>Common Language Runtime</em> (CLR).
|
---|
| 83 | <p> Another key concept is that of <em>managed code</em>. This is essentially
|
---|
| 84 | intermediate language code written in such a way that the CLR can take
|
---|
| 85 | care of the memory management, i.e. the CLR will do automatic garbage
|
---|
| 86 | collection, so the application code does not need to explicitly free
|
---|
| 87 | the memory for unused objects.
|
---|
| 88 | <p> The MS compilers for C# and VB.NET will only produce managed
|
---|
| 89 | code. Such programs cannot directly call normal, native functions
|
---|
| 90 | or classes. <a href="#footnote1"><sup>(1)</sup></a><a name="footnote-call1"></a>
|
---|
| 91 | <p> The MS C++ compiler for .NET on the other hand, can produce both
|
---|
| 92 | normal and managed code. To write a C++ class that can be compiled
|
---|
| 93 | into managed code, the developer must flag the class as managed using
|
---|
| 94 | the <tt>__gc</tt> keyword, and restrict the code to only use the subset of
|
---|
| 95 | C++ known as "Managed Extensions for C++", or MC++ for short. The
|
---|
| 96 | advantage is that MC++ code can freely call and use normal C++
|
---|
| 97 | functions and classes. And it also works the other way around: normal
|
---|
| 98 | C++ code can call managed functions and use managed classes (e.g. the
|
---|
| 99 | entire .NET framework class library), including managed functions and
|
---|
| 100 | classes implemented in C# or VB.NET. This feature of mixing managed
|
---|
| 101 | and normal C++ code immensely eases the interoperability with .NET,
|
---|
| 102 | and is by Microsoft referred to as the "It Just Works" (IJW) feature.
|
---|
| 103 | <p> This document demonstrates two different ways of integrating normal
|
---|
| 104 | C++ code (that uses Qt) with managed .NET code. First, the manual way
|
---|
| 105 | is presented, which includes using a thin MC++ wrapper class around
|
---|
| 106 | the normal Qt/C++ class. Then, the automated way is presented, which
|
---|
| 107 | utilizes the <a href="activeqt.html#ActiveQt">ActiveQt</a> framework as a generic bridge. The advantage of
|
---|
| 108 | the first method is that it gives the application developer full
|
---|
| 109 | control, while the second method requires less coding and relieves the
|
---|
| 110 | developer of dealing with the conversion between managed and normal
|
---|
| 111 | data objects.
|
---|
| 112 | <p> The impatient reader, who right away wants to see a <a href="qpushbutton.html">QPushButton</a> and a
|
---|
| 113 | custom Qt widget (<a href="qaxserver-example-multiple.html">QAxWidget2</a>) run in a .NET GUI application is referred to the example
|
---|
| 114 | directory of ActiveQt. It contains the result of this walkthrough
|
---|
| 115 | using both C# and VB.NET, created with Visual Studio.NET (not 2003).
|
---|
| 116 | Load <tt>examples/dotnet/walkthrough/csharp.csproj</tt>,
|
---|
| 117 | <tt>examples/dotnet/walkthrough/vb.vbproj</tt>
|
---|
| 118 | <a href="#footnote2"><sup>(2)</sup></a><a name="footnote-call2"></a>
|
---|
| 119 | or <tt>examples/dotnet/wrapper/wrapper.sln</tt> into the IDE and run
|
---|
| 120 | the solution.
|
---|
| 121 | <p> <h2> Walkthrough: .NET interop with MC++ and IJW
|
---|
| 122 | </h2>
|
---|
| 123 | <a name="2"></a><p> Normal C++ classes and functions can be used from managed .NET code by
|
---|
| 124 | providing thin wrapper classes written in MC++. The wrapper class will
|
---|
| 125 | take care of forwarding the calls to the normal C++ functions or
|
---|
| 126 | methods, and converting parameter data as necessary. Since the wrapper
|
---|
| 127 | class is a managed class, it can be used without further ado in any
|
---|
| 128 | managed .NET application, whether written in C#, VB.NET, MC++ or other
|
---|
| 129 | managed programming language.
|
---|
| 130 | <p>
|
---|
| 131 |
|
---|
| 132 | <pre> // native Qt/C++ class
|
---|
| 133 | class Worker : public <a href="qobject.html">QObject</a>
|
---|
| 134 | {
|
---|
| 135 | <a href="metaobjects.html#Q_OBJECT">Q_OBJECT</a>
|
---|
| 136 | Q_PROPERTY(QString statusString READ statusString WRITE setStatusString)
|
---|
| 137 | public:
|
---|
| 138 | Worker();
|
---|
| 139 |
|
---|
| 140 | <a href="qstring.html">QString</a> statusString() const;
|
---|
| 141 |
|
---|
| 142 | public slots:
|
---|
| 143 | void setStatusString(const <a href="qstring.html">QString</a> &string);
|
---|
| 144 |
|
---|
| 145 | signals:
|
---|
| 146 | void statusStringChanged(const <a href="qstring.html">QString</a> &string);
|
---|
| 147 |
|
---|
| 148 | private:
|
---|
| 149 | <a href="qstring.html">QString</a> status;
|
---|
| 150 | };
|
---|
| 151 | </pre>
|
---|
| 152 | <p> The Qt class has nothing unusual for Qt users, and as even the Qt
|
---|
| 153 | specialities like <tt>Q_PROPERTY</tt>, <tt>slots</tt> and <tt>signals</tt> are
|
---|
| 154 | implemented with straight C++ they don't cause any trouble when
|
---|
| 155 | compiling this class with any C++ compiler.
|
---|
| 156 | <p>
|
---|
| 157 |
|
---|
| 158 | <pre> class Worker;
|
---|
| 159 |
|
---|
| 160 | // .NET class
|
---|
| 161 | public __gc class netWorker
|
---|
| 162 | {
|
---|
| 163 | public:
|
---|
| 164 | netWorker();
|
---|
| 165 | ~netWorker();
|
---|
| 166 |
|
---|
| 167 | __property String *get_StatusString();
|
---|
| 168 | __property void set_StatusString(String *string);
|
---|
| 169 |
|
---|
| 170 | __event void statusStringChanged(String *args);
|
---|
| 171 |
|
---|
| 172 | private:
|
---|
| 173 | Worker *workerObject;
|
---|
| 174 | };
|
---|
| 175 | </pre>
|
---|
| 176 | <p> The .NET wrapper class uses keywords that are part of MC++ to indicate
|
---|
| 177 | that the class is managed/garbage collected (<tt>__gc</tt>), and that <tt>StatusString</tt> should be accessible as a property in languages that
|
---|
| 178 | support this concept (<tt>__property</tt>). We also declare an event
|
---|
| 179 | function <tt>statusStringChanged(String*)</tt> (<tt>__event</tt>), the
|
---|
| 180 | equivalent of the respective signal in the Qt class.
|
---|
| 181 | <p> Before we can start implementing the wrapper class we need a way to
|
---|
| 182 | convert Qt's datatypes (and potentionally your own) into .NET
|
---|
| 183 | datatypes, e.g. <a href="qstring.html">QString</a> objects need to be converted into objects
|
---|
| 184 | of type <tt>String*</tt>.
|
---|
| 185 | <p> When operating on managed objects in normal C++ code, a little extra
|
---|
| 186 | care must be taken because of the CLR's garbage collection. A normal
|
---|
| 187 | pointer variable should not <a href="#footnote3"><sup>(3)</sup></a><a name="footnote-call3"></a> be used to refer to a managed
|
---|
| 188 | object. The reason is that the garbage collection can kick in at any
|
---|
| 189 | time and move the object to another place on the heap, leaving you
|
---|
| 190 | with an invalid pointer.
|
---|
| 191 | <p> However, two methods are provided that solves this problem easily. The
|
---|
| 192 | first is to use a <em>pinned</em> pointer, i.e. declare the pointer variable
|
---|
| 193 | with the <tt>__pin</tt> keyword. This guarantees that the object pointed to
|
---|
| 194 | will not be moved by the garbage collector. It is recommended that
|
---|
| 195 | this method not be used to keep a references to managed objects for a
|
---|
| 196 | long time, since it will decrease the efficiency of the garbage
|
---|
| 197 | collector. The second way is to use the <tt>gcroot</tt> smartpointer
|
---|
| 198 | template type. This lets you create safe pointers to managed
|
---|
| 199 | objects. E.g. a variable of type <tt>gcroot<String></tt> will always point
|
---|
| 200 | to the String object, even if it has been moved by the garbage
|
---|
| 201 | collector, and it can be used just like a normal pointer.
|
---|
| 202 | <p>
|
---|
| 203 |
|
---|
| 204 | <pre> #include <<a href="qstring-h.html">qstring.h</a>>
|
---|
| 205 |
|
---|
| 206 | #using <mscorlib.dll>
|
---|
| 207 | #include <vcclr.h>
|
---|
| 208 |
|
---|
| 209 | using namespace System;
|
---|
| 210 |
|
---|
| 211 | String *QStringToString(const <a href="qstring.html">QString</a> &qstring)
|
---|
| 212 | {
|
---|
| 213 | <a name="x2467"></a> return new String(qstring.<a href="qstring.html#ucs2">ucs2</a>());
|
---|
| 214 | }
|
---|
| 215 | </pre>
|
---|
| 216 | <p> <pre> QString StringToQString(String *string)
|
---|
| 217 | {
|
---|
| 218 | wchar_t __pin *chars = PtrToStringChars(string);
|
---|
| 219 | return QString::fromUcs2(chars);
|
---|
| 220 | }
|
---|
| 221 | </pre>
|
---|
| 222 | <p> The convertor functions can then be used in the wrapper class
|
---|
| 223 | implementation to call the functions in the native C++ class.
|
---|
| 224 | <p>
|
---|
| 225 |
|
---|
| 226 | <pre> #include "networker.h"
|
---|
| 227 | #include "worker.h"
|
---|
| 228 | #include "tools.h"
|
---|
| 229 |
|
---|
| 230 | netWorker::netWorker()
|
---|
| 231 | {
|
---|
| 232 | workerObject = new Worker();
|
---|
| 233 | }
|
---|
| 234 | </pre>
|
---|
| 235 | <p> <pre> netWorker::~netWorker()
|
---|
| 236 | {
|
---|
| 237 | delete workerObject;
|
---|
| 238 | }
|
---|
| 239 | </pre>
|
---|
| 240 | <p> The constructor and destructor simply create and destroy the Qt
|
---|
| 241 | object wrapped using the C++ operators <tt>new</tt> and <tt>delete</tt>.
|
---|
| 242 | <p> <pre> String *netWorker::get_StatusString()
|
---|
| 243 | {
|
---|
| 244 | return QStringToString(workerObject->statusString());
|
---|
| 245 | }
|
---|
| 246 | </pre>
|
---|
| 247 | <p> The netWorker class delegates calls from the .NET code to the native
|
---|
| 248 | code. Although the transition between those two worlds implies a small
|
---|
| 249 | performance hit for each function call, and for the type conversion,
|
---|
| 250 | this should be negligible since we are anyway going to run within the
|
---|
| 251 | CLR.
|
---|
| 252 | <p> <pre> void netWorker::set_StatusString(String *string)
|
---|
| 253 | {
|
---|
| 254 | workerObject->setStatusString(StringToQString(string));
|
---|
| 255 | __raise statusStringChanged(string);
|
---|
| 256 | }
|
---|
| 257 | </pre>
|
---|
| 258 | <p> The property setter calls the native Qt class before firing the
|
---|
| 259 | event using the <tt>__raise</tt> keyword.
|
---|
| 260 | <p> This wrapper class can now be used in .NET code, e.g. using C++, C#,
|
---|
| 261 | Visual Basic or any other programming language available for .NET.
|
---|
| 262 | <p>
|
---|
| 263 |
|
---|
| 264 | <pre> using System;
|
---|
| 265 |
|
---|
| 266 | namespace WrapperApp
|
---|
| 267 | {
|
---|
| 268 | class App
|
---|
| 269 | {
|
---|
| 270 | void Run()
|
---|
| 271 | {
|
---|
| 272 | netWorker worker = new netWorker();
|
---|
| 273 |
|
---|
| 274 | worker.statusStringChanged += new netWorker.__Delegate_statusStringChanged(onStatusStringChanged);
|
---|
| 275 |
|
---|
| 276 | System.Console.Out.WriteLine(worker.StatusString);
|
---|
| 277 |
|
---|
| 278 | System.Console.Out.WriteLine("Working cycle begins...");
|
---|
| 279 | worker.StatusString = "Working";
|
---|
| 280 | worker.StatusString = "Lunch Break";
|
---|
| 281 | worker.StatusString = "Working";
|
---|
| 282 | worker.StatusString = "Idle";
|
---|
| 283 | System.Console.Out.WriteLine("Working cycle ends...");
|
---|
| 284 | }
|
---|
| 285 |
|
---|
| 286 | private void onStatusStringChanged(string str)
|
---|
| 287 | {
|
---|
| 288 | System.Console.Out.WriteLine(str);
|
---|
| 289 | }
|
---|
| 290 |
|
---|
| 291 | [STAThread]
|
---|
| 292 | static void Main(string[] args)
|
---|
| 293 | {
|
---|
| 294 | App app = new App();
|
---|
| 295 | app.Run();
|
---|
| 296 | }
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
| 299 | </pre>
|
---|
| 300 | <p> <h2> Walkthrough: .NET/COM Interop with ActiveQt
|
---|
| 301 | </h2>
|
---|
| 302 | <a name="3"></a><p> Fortunately .NET provides a generic wrapper for COM objects, the
|
---|
| 303 | <em>Runtime Callable Wrapper</em> (RCW). This RCW is a proxy for the
|
---|
| 304 | COM object and is generated by the CLR when a .NET Framework client
|
---|
| 305 | activates a COM object. This provides a generic way to reuse COM
|
---|
| 306 | objects in a .NET Framework project.
|
---|
| 307 | <p> Making a <a href="qobject.html">QObject</a> class into a COM object is easily achieved with
|
---|
| 308 | ActiveQt and demonstrated in the <a href="qaxserver-examples.html">examples</a>. The walkthrough will use the Qt classes implemented
|
---|
| 309 | in those examples, so the first thing to do is to make sure that those
|
---|
| 310 | examples have been built correctly, e.g. by opening the <a href="qaxserver-demo-multiple.html">demonstration pages</a> in Internet
|
---|
| 311 | Explorer to verify that the controls are functional.
|
---|
| 312 | <p> <h3> Starting a Project
|
---|
| 313 | </h3>
|
---|
| 314 | <a name="3-1"></a><p> Start Visual Studio.NET, and create a new C# project for writing a
|
---|
| 315 | Windows application. This will present you with an empty form in
|
---|
| 316 | Visual Studio's dialog editor. You should see the toolbox, which
|
---|
| 317 | presents you with a number of available controls and objects in
|
---|
| 318 | different categories. If you right-click on the toolbox it allows
|
---|
| 319 | you to add new tabs. We will add the tab "Qt".
|
---|
| 320 | <p> <h3> Importing Qt Widgets
|
---|
| 321 | </h3>
|
---|
| 322 | <a name="3-2"></a><p> The category only has a pointer tool by default, and we have to add
|
---|
| 323 | the Qt objects we want to use in our form. Right-click on the empty
|
---|
| 324 | space, and select "Customize". This opens a dialog that has two
|
---|
| 325 | tabs, "COM Components" and ".NET Framework Components". We used
|
---|
| 326 | ActiveQt to wrap QWidgets into COM objects, so we select the "COM
|
---|
| 327 | Components" page, and look for the classes we want to use, e.g.
|
---|
| 328 | "QPushButton" and "QAxWidget2".
|
---|
| 329 | <p> When we select those widgets and close the dialog the two widgets
|
---|
| 330 | will now be available from the toolbox as grey squares with their
|
---|
| 331 | name next to it <a href="#footnote4"><sup>(4)</sup></a><a name="footnote-call4"></a> .
|
---|
| 332 | <p> <h3> Using Qt Widgets
|
---|
| 333 | </h3>
|
---|
| 334 | <a name="3-3"></a><p> We can now add an instance of QAxWidget2 and a <a href="qpushbutton.html">QPushButton</a> to
|
---|
| 335 | the form. Visual Studio will automatically generate the RCW for the
|
---|
| 336 | object servers. The QAxWidget2 instance takes most of the upper
|
---|
| 337 | part of the form, with the QPushButton in the lower right corner.
|
---|
| 338 | <p> In the property editor of Visual Studio we can modify the properties
|
---|
| 339 | of our controls - QPushButton exposes the <a href="qwidget.html">QWidget</a> API and has many
|
---|
| 340 | properties, while QAxWidget2 has only the Visual Studio standard
|
---|
| 341 | properties in addition to its own property "lineWidth" in the
|
---|
| 342 | "Miscellaneous" category. The objects are named "axQPushButton1" and
|
---|
| 343 | "axQAxWidget21", and since especially the last name is a bit
|
---|
| 344 | confusing we rename the objects to "resetButton" and "circleWidget".
|
---|
| 345 | <p> We can also change the Qt properties, e.g. set the "text" property
|
---|
| 346 | of the <tt>resetButton</tt> to "Reset", and the "lineWidth" property of the
|
---|
| 347 | <tt>circleWidget</tt> to 5. We can also put those objects into the layout
|
---|
| 348 | system that Visual Studio's dialog editor provides, e.g. by setting
|
---|
| 349 | the anchors of the <tt>circleWidget</tt> to "Left, Top, Right, Bottom", and
|
---|
| 350 | the anchors of the <tt>resetButton</tt> to "Bottom, Right".
|
---|
| 351 | <p> Now we can compile and start the project, which will open a user
|
---|
| 352 | interface with our two Qt widgets. If we can resize the dialog,
|
---|
| 353 | the widgets will resize appropriately.
|
---|
| 354 | <p> <h3> Handling Qt Signals
|
---|
| 355 | </h3>
|
---|
| 356 | <a name="3-4"></a><p> We will now implement event handlers for the widgets. Select the
|
---|
| 357 | <tt>circleWidget</tt> and select the "Events" page in the property
|
---|
| 358 | editor. The widget exposes events because the QAxWidget2 class has
|
---|
| 359 | the "StockEvents" attribute set in its class definition. We implement
|
---|
| 360 | the event handler <tt>circleClicked</tt> for the <tt>ClickEvent</tt> to increase
|
---|
| 361 | the line width by one for every click:
|
---|
| 362 | <p>
|
---|
| 363 |
|
---|
| 364 | <pre> private void circleClicked(object sender, System.EventArgs e)
|
---|
| 365 | {
|
---|
| 366 | this.circleWidget.lineWidth++;
|
---|
| 367 | }
|
---|
| 368 | </pre>
|
---|
| 369 | <p> In general we can implement a default event handler by double
|
---|
| 370 | clicking on the widget in the form, but the default events for
|
---|
| 371 | our widgets are right now not defined.
|
---|
| 372 | <p> We will also implement an event handler for the <tt>clicked</tt> signal
|
---|
| 373 | emitted by <a href="qpushbutton.html">QPushButton</a>. Add the event handler <tt>resetLineWidth</tt> to
|
---|
| 374 | the <tt>clicked</tt> event, and implement the generated function:
|
---|
| 375 | <p> <pre> private void resetLineWidth(object sender, System.EventArgs e)
|
---|
| 376 | {
|
---|
| 377 | this.circleWidget.lineWidth = 1;
|
---|
| 378 | this.resetButton.setFocus();
|
---|
| 379 | }
|
---|
| 380 | </pre>
|
---|
| 381 | <p> We reset the property to 1, and also call the <tt>setFocus()</tt> slot
|
---|
| 382 | to simulate the user style on Windows, where a button grabs focus
|
---|
| 383 | when you click it (so that you can click it again with the spacebar).
|
---|
| 384 | <p> If we now compile and run the project we can click on the circle
|
---|
| 385 | widget to increase its line width, and press the reset button to
|
---|
| 386 | set the line width back to 1.
|
---|
| 387 | <p> <h2> Summary
|
---|
| 388 | </h2>
|
---|
| 389 | <a name="4"></a><p> Using ActiveQt as a universal interoperability bridge between the
|
---|
| 390 | .NET world and the native world of Qt is very easy, and makes it
|
---|
| 391 | often unnecessary to implement a lot of handwritten wrapper classes.
|
---|
| 392 | Instead, the <a href="qaxfactory.html">QAxFactory</a> implementation in the otherwise completely
|
---|
| 393 | cross-platform Qt project provides the glue that .NET needs to to
|
---|
| 394 | generate the RCW.
|
---|
| 395 | <p> If this is not sufficient we can implement our own wrapper classes
|
---|
| 396 | thanks to the C++ extensions provided by Microsoft.
|
---|
| 397 | <p> <h3> Limitations
|
---|
| 398 | </h3>
|
---|
| 399 | <a name="4-1"></a><p> All the limitations when using ActiveQt are implied when using this
|
---|
| 400 | technique to interoperate with .NET, e.g. the datatypes we can use
|
---|
| 401 | in the APIs can only be those supported by ActiveQt and COM. However,
|
---|
| 402 | since this includes subclasses of <a href="qobject.html">QObject</a> and <a href="qwidget.html">QWidget</a> we can wrap
|
---|
| 403 | any of our datatypes into a QObject subclass to make its API
|
---|
| 404 | available to .NET. This has the positive side effect that the same
|
---|
| 405 | API is automatically available in <a href="http://www.trolltech.com/products/qsa">QSA</a>, the cross platform
|
---|
| 406 | scripting solution for Qt applications, and to COM clients in general.
|
---|
| 407 | <p> When using the "IJW" method, in priciple the only limitation is the
|
---|
| 408 | time required to write the wrapper classes and data type conversion
|
---|
| 409 | functions.
|
---|
| 410 | <p> <h3> Performance Considerations
|
---|
| 411 | </h3>
|
---|
| 412 | <a name="4-2"></a><p> Every call from CLR bytecode to native code implies a small
|
---|
| 413 | performance hit, and necessary type conversions introduce an
|
---|
| 414 | additional delay with every layer that exists between the two
|
---|
| 415 | frameworks. Consequently every approach to mix .NET and native
|
---|
| 416 | code should try to minimize the communication necessary between
|
---|
| 417 | the different worlds.
|
---|
| 418 | <p> As ActiveQt introduces three layers at once - the RCW, COM and finally
|
---|
| 419 | ActiveQt itself - the performance penalty when using the generic
|
---|
| 420 | Qt/ActiveQt/COM/RCW/.NET bridge is larger than when using a
|
---|
| 421 | hand-crafted IJW-wrapper class. The execution speed however is still
|
---|
| 422 | sufficient for connecting to and modifying interactive elements in a
|
---|
| 423 | user interface, and as soon as the benefit of using Qt and C++ to
|
---|
| 424 | implement and compile performance critical algorithms into native code
|
---|
| 425 | kicks in, ActiveQt becomes a valid choice for making even non-visual
|
---|
| 426 | parts of your application accessible to .NET.
|
---|
| 427 | <p>
|
---|
| 428 | <hr>
|
---|
| 429 | <ol> <li><a name="footnote1"></a>
|
---|
| 430 | The .NET framework provides Platform Invocation
|
---|
| 431 | Services - P/Invoke - that enable managed code to call native C (not
|
---|
| 432 | C++) functions located in DLLs directly. The resulting application
|
---|
| 433 | then becomes partially unmanaged. <a href="#footnote-call1">Back...</a> <li><a name="footnote2"></a>
|
---|
| 434 |
|
---|
| 435 | You will notice that in the generated code the following line is
|
---|
| 436 | commented out: <pre>
|
---|
| 437 | ' VB is case insensitive, but our C++ controls are not.
|
---|
| 438 | ' Me.resetButton.enabled = True
|
---|
| 439 | </pre>
|
---|
| 440 |
|
---|
| 441 | This line is regenerated without comment whenever you change the
|
---|
| 442 | dialog, in which case you have to comment it out again to be able
|
---|
| 443 | to run the project. This is a bug in the original version of
|
---|
| 444 | Visual Studio.NET, and is fixed in the 2003 edition.
|
---|
| 445 | <a href="#footnote-call2">Back...</a> <li><a name="footnote3"></a>
|
---|
| 446 | Indeed, the compiler will in
|
---|
| 447 | many cases disallow it. <a href="#footnote-call3">Back...</a> <li><a name="footnote4"></a>
|
---|
| 448 | Icons could be added by modifying the
|
---|
| 449 | way the controls register themselves. <a href="#footnote-call4">Back...</a></ol>
|
---|
| 450 | </hr><p>See also <a href="qaxserver-examples.html">The QAxServer Examples</a>.
|
---|
| 451 |
|
---|
| 452 | <!-- eof -->
|
---|
| 453 | <p><address><hr><div align=center>
|
---|
| 454 | <table width=100% cellspacing=0 border=0><tr>
|
---|
| 455 | <td>Copyright © 2007
|
---|
| 456 | <a href="troll.html">Trolltech</a><td align=center><a href="trademarks.html">Trademarks</a>
|
---|
| 457 | <td align=right><div align=right>Qt 3.3.8</div>
|
---|
| 458 | </table></div></address></body>
|
---|
| 459 | </html>
|
---|