Added entry for DirectSoundFullDuplexCreate.
[wine] / documentation / ole.sgml
1   <chapter id="ole">
2     <title>COM/OLE in Wine</title>
3
4     <sect1 id="ole-architecture">
5       <title>COM/OLE Architecture in Wine</title>
6
7       <para>
8         The section goes into detail about how COM/OLE2 are
9         implemented in Wine.
10       </para>
11     </sect1>
12
13     <sect1 id="ole-binary">
14       <title>Using Binary OLE components in Wine</title>
15       <para>
16         This section describes how to import pre-compiled COM/OLE
17         components...
18       </para>
19     </sect1>
20
21     <sect1 id="com-writing">
22       <title>Writing OLE Components for Wine</title>
23
24       <para>
25         Based on the comments in <filename>wine/include/wine/obj_base.h</filename>.
26       </para>
27       <para>
28         This section describes how to create your own natively
29         compiled COM/OLE components.
30       </para>
31
32       <sect2>
33         <title>Macros to define a COM interface</title>
34
35         <para>
36           The goal of the following set of definitions is to provide a
37           way to use the same header file definitions to provide both
38           a C interface and a C++ object oriented interface to COM
39           interfaces. The type of interface is selected automatically
40           depending on the language but it is always possible to get
41           the C interface in C++ by defining CINTERFACE.
42         </para>
43         <para>
44           It is based on the following assumptions:
45         </para>
46         <itemizedlist>
47           <listitem>
48             <para>
49               all COM interfaces derive from IUnknown, this should not
50               be a problem.
51             </para>
52           </listitem>
53           <listitem>
54             <para>
55               the header file only defines the interface, the actual
56               fields are defined separately in the C file implementing
57               the interface.
58             </para>
59           </listitem>
60         </itemizedlist>
61         <para>
62           The natural approach to this problem would be to make sure
63           we get a C++ class and virtual methods in C++ and a
64           structure with a table of pointer to functions in C.
65           Unfortunately the layout of the virtual table is compiler
66           specific, the layout of g++ virtual tables is not the same
67           as that of an egcs virtual table which is not the same as
68           that generated by Visual C+. There are workarounds to make
69           the virtual tables compatible via padding but unfortunately
70           the one which is imposed to the Wine emulator by the Windows
71           binaries, i.e. the Visual C++ one, is the most compact of
72           all.
73         </para>
74         <para>
75           So the solution I finally adopted does not use virtual
76           tables. Instead I use inline non virtual methods that
77           dereference the method pointer themselves and perform the
78           call.
79         </para>
80         <para>
81           Let's take Direct3D as an example:
82         </para>
83         <programlisting>#define ICOM_INTERFACE IDirect3D
84 #define IDirect3D_METHODS \
85     ICOM_METHOD1(HRESULT,Initialize,    REFIID,) \
86     ICOM_METHOD2(HRESULT,EnumDevices,   LPD3DENUMDEVICESCALLBACK,, LPVOID,) \
87     ICOM_METHOD2(HRESULT,CreateLight,   LPDIRECT3DLIGHT*,, IUnknown*,) \
88     ICOM_METHOD2(HRESULT,CreateMaterial,LPDIRECT3DMATERIAL*,, IUnknown*,) \
89     ICOM_METHOD2(HRESULT,CreateViewport,LPDIRECT3DVIEWPORT*,, IUnknown*,) \
90     ICOM_METHOD2(HRESULT,FindDevice,    LPD3DFINDDEVICESEARCH,, LPD3DFINDDEVICERESULT,)
91 #define IDirect3D_IMETHODS \
92     IUnknown_IMETHODS \
93     IDirect3D_METHODS
94 ICOM_DEFINE(IDirect3D,IUnknown)
95 #undef ICOM_INTERFACE
96
97 #ifdef ICOM_CINTERFACE
98 // *** IUnknown methods *** //
99 #define IDirect3D_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b)
100 #define IDirect3D_AddRef(p)             ICOM_CALL (AddRef,p)
101 #define IDirect3D_Release(p)            ICOM_CALL (Release,p)
102 // *** IDirect3D methods *** //
103 #define IDirect3D_Initialize(p,a)       ICOM_CALL1(Initialize,p,a)
104 #define IDirect3D_EnumDevices(p,a,b)    ICOM_CALL2(EnumDevice,p,a,b)
105 #define IDirect3D_CreateLight(p,a,b)    ICOM_CALL2(CreateLight,p,a,b)
106 #define IDirect3D_CreateMaterial(p,a,b) ICOM_CALL2(CreateMaterial,p,a,b)
107 #define IDirect3D_CreateViewport(p,a,b) ICOM_CALL2(CreateViewport,p,a,b)
108 #define IDirect3D_FindDevice(p,a,b)     ICOM_CALL2(FindDevice,p,a,b)
109 #endif</programlisting>
110         <para>
111           Comments:
112         </para>
113         <para>
114           The ICOM_INTERFACE macro is used in the ICOM_METHOD macros
115           to define the type of the 'this' pointer. Defining this
116           macro here saves us the trouble of having to repeat the
117           interface name everywhere. Note however that because of the
118           way macros work, a macro like ICOM_METHOD1 cannot use
119           'ICOM_INTERFACE##_VTABLE' because this would give
120           'ICOM_INTERFACE_VTABLE' and not 'IDirect3D_VTABLE'.
121         </para>
122         <para>
123           ICOM_METHODS defines the methods specific to this
124           interface. It is then aggregated with the inherited methods
125           to form ICOM_IMETHODS.
126         </para>
127         <para>
128           ICOM_IMETHODS defines the list of methods that are
129           inheritable from this interface. It must be written manually
130           (rather than using a macro to generate the equivalent code)
131           to avoid macro recursion (which compilers don't like).
132         </para>
133         <para>
134           The ICOM_DEFINE finally declares all the structures
135           necessary for the interface. We have to explicitly use the
136           interface name for macro expansion reasons again.  Inherited
137           methods are inherited in C by using the IDirect3D_METHODS
138           macro and the parent's Xxx_IMETHODS macro. In C++ we need
139           only use the IDirect3D_METHODS since method inheritance is
140           taken care of by the language.
141         </para>
142         <para>
143           In C++ the ICOM_METHOD macros generate a function prototype
144           and a call to a function pointer method. This means using
145           once 't1 p1, t2 p2, ...' and once 'p1, p2' without the
146           types. The only way I found to handle this is to have one
147           ICOM_METHOD macro per number of parameters and to have it
148           take only the type information (with const if necessary) as
149           parameters.  The 'undef ICOM_INTERFACE' is here to remind
150           you that using ICOM_INTERFACE in the following macros will
151           not work. This time it's because the ICOM_CALL macro
152           expansion is done only once the 'IDirect3D_Xxx' macro is
153           expanded. And by that time ICOM_INTERFACE will be long gone
154           anyway.
155         </para>
156         <para>
157           You may have noticed the double commas after each parameter
158           type. This allows you to put the name of that parameter
159           which I think is good for documentation. It is not required
160           and since I did not know what to put there for this example
161           (I could only find doc about IDirect3D2), I left them blank.
162         </para>
163         <para>
164           Finally the set of 'IDirect3D_Xxx' macros is a standard set
165           of macros defined to ease access to the interface methods in
166           C. Unfortunately I don't see any way to avoid having to
167           duplicate the inherited method definitions there. This time
168           I could have used a trick to use only one macro whatever the
169           number of parameters but I prefered to have it work the same
170           way as above.
171         </para>
172         <para>
173           You probably have noticed that we don't define the fields we
174           need to actually implement this interface: reference count,
175           pointer to other resources and miscellaneous fields. That's
176           because these interfaces are just that: interfaces. They may
177           be implemented more than once, in different contexts and
178           sometimes not even in Wine. Thus it would not make sense to
179           impose that the interface contains some specific fields.
180         </para>
181       </sect2>
182
183       <sect2>
184         <title>Bindings in C</title>
185
186         <para>
187           In C this gives:
188         </para>
189         <programlisting>typedef struct IDirect3DVtbl IDirect3DVtbl;
190 struct IDirect3D {
191     IDirect3DVtbl* lpVtbl;
192 };
193 struct IDirect3DVtbl {
194     HRESULT (*fnQueryInterface)(IDirect3D* me, REFIID riid, LPVOID* ppvObj);
195     ULONG (*fnAddRef)(IDirect3D* me);
196     ULONG (*fnRelease)(IDirect3D* me);
197     HRESULT (*fnInitialize)(IDirect3D* me, REFIID a);
198     HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b);
199     HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b);
200     HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b);
201     HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b);
202     HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b);
203 }; 
204
205 #ifdef ICOM_CINTERFACE
206 // *** IUnknown methods *** //
207 #define IDirect3D_QueryInterface(p,a,b) (p)->lpVtbl->fnQueryInterface(p,a,b)
208 #define IDirect3D_AddRef(p)             (p)->lpVtbl->fnAddRef(p)
209 #define IDirect3D_Release(p)            (p)->lpVtbl->fnRelease(p)
210 // *** IDirect3D methods *** //
211 #define IDirect3D_Initialize(p,a)       (p)->lpVtbl->fnInitialize(p,a)
212 #define IDirect3D_EnumDevices(p,a,b)    (p)->lpVtbl->fnEnumDevice(p,a,b)
213 #define IDirect3D_CreateLight(p,a,b)    (p)->lpVtbl->fnCreateLight(p,a,b)
214 #define IDirect3D_CreateMaterial(p,a,b) (p)->lpVtbl->fnCreateMaterial(p,a,b)
215 #define IDirect3D_CreateViewport(p,a,b) (p)->lpVtbl->fnCreateViewport(p,a,b)
216 #define IDirect3D_FindDevice(p,a,b)     (p)->lpVtbl->fnFindDevice(p,a,b)
217 #endif</programlisting>
218         <para>
219           Comments:
220         </para>
221         <para>
222           IDirect3D only contains a pointer to the IDirect3D
223           virtual/jump table. This is the only thing the user needs to
224           know to use the interface. Of course the structure we will
225           define to implement this interface will have more fields but
226           the first one will match this pointer.
227         </para>
228         <para>
229           The code generated by ICOM_DEFINE defines both the structure
230           representing the interface and the structure for the jump
231           table. ICOM_DEFINE uses the parent's Xxx_IMETHODS macro to
232           automatically repeat the prototypes of all the inherited
233           methods and then uses IDirect3D_METHODS to define the
234           IDirect3D methods.
235         </para>
236         <para>
237           Each method is declared as a pointer to function field in
238           the jump table. The implementation will fill this jump table
239           with appropriate values, probably using a static variable,
240           and initialize the lpVtbl field to point to this variable.
241         </para>
242         <para>
243           The IDirect3D_Xxx macros then just derefence the lpVtbl
244           pointer and use the function pointer corresponding to the
245           macro name. This emulates the behavior of a virtual table
246           and should be just as fast.
247         </para>
248         <para>
249           This C code should be quite compatible with the Windows
250           headers both for code that uses COM interfaces and for code
251           implementing a COM interface.
252         </para>
253       </sect2>
254
255       <sect2>
256         <title>Bindings in C++</title>
257         <para>
258           And in C++ (with gcc's g++):
259         </para>
260         <programlisting>typedef struct IDirect3D: public IUnknown {
261     private: HRESULT (*fnInitialize)(IDirect3D* me, REFIID a);
262     public: inline HRESULT Initialize(REFIID a) { return ((IDirect3D*)t.lpVtbl)->fnInitialize(this,a); };
263     private: HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b);
264     public: inline HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK a, LPVOID b)
265         { return ((IDirect3D*)t.lpVtbl)->fnEnumDevices(this,a,b); };
266     private: HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b);
267     public: inline HRESULT CreateLight(LPDIRECT3DLIGHT* a, IUnknown* b)
268         { return ((IDirect3D*)t.lpVtbl)->fnCreateLight(this,a,b); };
269     private: HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b);
270     public: inline HRESULT CreateMaterial(LPDIRECT3DMATERIAL* a, IUnknown* b)
271         { return ((IDirect3D*)t.lpVtbl)->fnCreateMaterial(this,a,b); };
272     private: HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b);
273     public: inline HRESULT CreateViewport(LPDIRECT3DVIEWPORT* a, IUnknown* b)
274         { return ((IDirect3D*)t.lpVtbl)->fnCreateViewport(this,a,b); };
275     private:  HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b);
276     public: inline HRESULT FindDevice(LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b)
277         { return ((IDirect3D*)t.lpVtbl)->fnFindDevice(this,a,b); };
278 };</programlisting>
279         <para>
280           Comments:
281         </para>
282         <para>
283           In C++ IDirect3D does double duty as both the virtual/jump
284           table and as the interface definition. The reason for this
285           is to avoid having to duplicate the mehod definitions: once
286           to have the function pointers in the jump table and once to
287           have the methods in the interface class. Here one macro can
288           generate both. This means though that the first pointer,
289           t.lpVtbl defined in IUnknown, must be interpreted as the
290           jump table pointer if we interpret the structure as the
291           interface class, and as the function pointer to the
292           QueryInterface method, t.fnQueryInterface, if we interpret
293           the structure as the jump table. Fortunately this gymnastic
294           is entirely taken care of in the header of IUnknown.
295         </para>
296         <para>
297           Of course in C++ we use inheritance so that we don't have to
298           duplicate the method definitions.
299         </para>
300         <para>
301           Since IDirect3D does double duty, each ICOM_METHOD macro
302           defines both a function pointer and a non-virtual inline
303           method which dereferences it and calls it. This way this
304           method behaves just like a virtual method but does not
305           create a true C++ virtual table which would break the
306           structure layout. If you look at the implementation of these
307           methods you'll notice that they would not work for void
308           functions. We have to return something and fortunately this
309           seems to be what all the COM methods do (otherwise we would
310           need another set of macros).
311         </para>
312         <para>
313           Note how the ICOM_METHOD generates both function prototypes
314           mixing types and formal parameter names and the method
315           invocation using only the formal parameter name. This is the
316           reason why we need different macros to handle different
317           numbers of parameters.
318         </para>
319         <para>
320           Finally there is no IDirect3D_Xxx macro. These are not
321           needed in C++ unless the CINTERFACE macro is defined in
322           which case we would not be here.
323         </para>
324         <para>
325           This C++ code works well for code that just uses COM
326           interfaces. But it will not work with C++ code implement a
327           COM interface. That's because such code assumes the
328           interface methods are declared as virtual C++ methods which
329           is not the case here.
330         </para>
331       </sect2>
332
333       <sect2>
334         <title>Implementing a COM interface.</title>
335
336         <para>
337           This continues the above example. This example assumes that
338           the implementation is in C.
339         </para>
340         <programlisting>typedef struct _IDirect3D {
341     void* lpVtbl;
342     // ...
343  } _IDirect3D;
344
345 static ICOM_VTABLE(IDirect3D) d3dvt;
346
347 // implement the IDirect3D methods here
348
349 int IDirect3D_fnQueryInterface(IDirect3D* me)
350 {
351     ICOM_THIS(IDirect3D,me);
352     // ...
353 }
354
355 // ...
356
357 static ICOM_VTABLE(IDirect3D) d3dvt = {
358     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
359     IDirect3D_fnQueryInterface,
360     IDirect3D_fnAdd,
361     IDirect3D_fnAdd2,
362     IDirect3D_fnInitialize,
363     IDirect3D_fnSetWidth
364 };</programlisting>
365         <para>
366           Comments:
367         </para>
368         <para>
369           We first define what the interface really contains. This is
370           the _IDirect3D structure. The first field must of course be
371           the virtual table pointer. Everything else is free.
372         </para>
373         <para>
374           Then we predeclare our static virtual table variable, we
375           will need its address in some methods to initialize the
376           virtual table pointer of the returned interface objects.
377         </para>
378         <para>
379           Then we implement the interface methods. To match what has
380           been declared in the header file they must take a pointer to
381           a IDirect3D structure and we must cast it to an _IDirect3D
382           so that we can manipulate the fields. This is performed by
383           the ICOM_THIS macro.
384         </para>
385         <para>
386           Finally we initialize the virtual table.
387         </para>
388       </sect2>
389     </sect1>
390   </chapter>
391
392 <!-- Keep this comment at the end of the file
393 Local variables:
394 mode: sgml
395 sgml-parent-document:("wine-doc.sgml" "set" "book" "part" "chapter" "")
396 End:
397 -->