|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the documentation of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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://qt.nokia.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 */ |