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

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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