source: trunk/doc/src/examples/activeqt/dotnet.qdoc@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 17.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the documentation of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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://qtsoftware.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*/
Note: See TracBrowser for help on using the repository browser.