wineclipsrv is no longer used, remove it.
[wine] / documentation / ole.sgml
1   <chapter id="ole">
2     <title>COM in Wine</title>
3
4     <sect1 id="com-writing">
5       <title>Writing COM Components for Wine</title>
6
7       <para>
8         This section describes how to create your own natively
9         compiled COM components.
10       </para>
11
12       <sect2>
13         <title>Macros to define a COM interface</title>
14
15         <para>
16           The goal of the following set of definitions is to provide a
17           way to use the same header file definitions to provide both
18           a C interface and a C++ object oriented interface to COM
19           interfaces. The type of interface is selected automatically
20           depending on the language but it is always possible to get
21           the C interface in C++ by defining CINTERFACE.
22         </para>
23         <para>
24           It is based on the following assumptions:
25         </para>
26         <itemizedlist>
27           <listitem>
28             <para>
29               all COM interfaces derive from IUnknown, this should not
30               be a problem.
31             </para>
32           </listitem>
33           <listitem>
34             <para>
35               the header file only defines the interface, the actual
36               fields are defined separately in the C file implementing
37               the interface.
38             </para>
39           </listitem>
40         </itemizedlist>
41         <para>
42           The natural approach to this problem would be to make sure
43           we get a C++ class and virtual methods in C++ and a
44           structure with a table of pointer to functions in C.
45           Unfortunately the layout of the virtual table is compiler
46           specific, the layout of g++ virtual tables is not the same
47           as that of an egcs virtual table which is not the same as
48           that generated by Visual C++. There are work arounds to make
49           the virtual tables compatible via padding but unfortunately
50           the one which is imposed to the Wine emulator by the Windows
51           binaries, i.e. the Visual C++ one, is the most compact of
52           all.
53         </para>
54         <para>
55           So the solution I finally adopted does not use virtual
56           tables. Instead I use in-line non virtual methods that
57           dereference the method pointer themselves and perform the
58           call.
59         </para>
60         <para>
61           Let's take Direct3D as an example:
62         </para>
63         <programlisting>#define ICOM_INTERFACE IDirect3D
64 #define IDirect3D_METHODS \
65     ICOM_METHOD1(HRESULT,Initialize,    REFIID,) \
66     ICOM_METHOD2(HRESULT,EnumDevices,   LPD3DENUMDEVICESCALLBACK,, LPVOID,) \
67     ICOM_METHOD2(HRESULT,CreateLight,   LPDIRECT3DLIGHT*,, IUnknown*,) \
68     ICOM_METHOD2(HRESULT,CreateMaterial,LPDIRECT3DMATERIAL*,, IUnknown*,) \
69     ICOM_METHOD2(HRESULT,CreateViewport,LPDIRECT3DVIEWPORT*,, IUnknown*,) \
70     ICOM_METHOD2(HRESULT,FindDevice,    LPD3DFINDDEVICESEARCH,, LPD3DFINDDEVICERESULT,)
71 #define IDirect3D_IMETHODS \
72     IUnknown_IMETHODS \
73     IDirect3D_METHODS
74 ICOM_DEFINE(IDirect3D,IUnknown)
75 #undef ICOM_INTERFACE
76
77 #ifdef ICOM_CINTERFACE
78 // *** IUnknown methods *** //
79 #define IDirect3D_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b)
80 #define IDirect3D_AddRef(p)             ICOM_CALL (AddRef,p)
81 #define IDirect3D_Release(p)            ICOM_CALL (Release,p)
82 // *** IDirect3D methods *** //
83 #define IDirect3D_Initialize(p,a)       ICOM_CALL1(Initialize,p,a)
84 #define IDirect3D_EnumDevices(p,a,b)    ICOM_CALL2(EnumDevice,p,a,b)
85 #define IDirect3D_CreateLight(p,a,b)    ICOM_CALL2(CreateLight,p,a,b)
86 #define IDirect3D_CreateMaterial(p,a,b) ICOM_CALL2(CreateMaterial,p,a,b)
87 #define IDirect3D_CreateViewport(p,a,b) ICOM_CALL2(CreateViewport,p,a,b)
88 #define IDirect3D_FindDevice(p,a,b)     ICOM_CALL2(FindDevice,p,a,b)
89 #endif</programlisting>
90         <para>
91           Comments:
92         </para>
93         <para>
94           The ICOM_INTERFACE macro is used in the ICOM_METHOD macros
95           to define the type of the 'this' pointer. Defining this
96           macro here saves us the trouble of having to repeat the
97           interface name everywhere. Note however that because of the
98           way macros work, a macro like ICOM_METHOD1 cannot use
99           'ICOM_INTERFACE##_VTABLE' because this would give
100           'ICOM_INTERFACE_VTABLE' and not 'IDirect3D_VTABLE'.
101         </para>
102         <para>
103           ICOM_METHODS defines the methods specific to this
104           interface. It is then aggregated with the inherited methods
105           to form ICOM_IMETHODS.
106         </para>
107         <para>
108           ICOM_IMETHODS defines the list of methods that are
109           inheritable from this interface. It must be written manually
110           (rather than using a macro to generate the equivalent code)
111           to avoid macro recursion (which compilers don't like).
112         </para>
113         <para>
114           The ICOM_DEFINE finally declares all the structures
115           necessary for the interface. We have to explicitly use the
116           interface name for macro expansion reasons again.  Inherited
117           methods are inherited in C by using the IDirect3D_METHODS
118           macro and the parent's Xxx_IMETHODS macro. In C++ we need
119           only use the IDirect3D_METHODS since method inheritance is
120           taken care of by the language.
121         </para>
122         <para>
123           In C++ the ICOM_METHOD macros generate a function prototype
124           and a call to a function pointer method. This means using
125           once 't1 p1, t2 p2, ...' and once 'p1, p2' without the
126           types. The only way I found to handle this is to have one
127           ICOM_METHOD macro per number of parameters and to have it
128           take only the type information (with const if necessary) as
129           parameters.  The 'undef ICOM_INTERFACE' is here to remind
130           you that using ICOM_INTERFACE in the following macros will
131           not work. This time it's because the ICOM_CALL macro
132           expansion is done only once the 'IDirect3D_Xxx' macro is
133           expanded. And by that time ICOM_INTERFACE will be long gone
134           anyway.
135         </para>
136         <para>
137           You may have noticed the double commas after each parameter
138           type. This allows you to put the name of that parameter
139           which I think is good for documentation. It is not required
140           and since I did not know what to put there for this example
141           (I could only find doc about IDirect3D2), I left them blank.
142         </para>
143         <para>
144           Finally the set of 'IDirect3D_Xxx' macros is a standard set
145           of macros defined to ease access to the interface methods in
146           C. Unfortunately I don't see any way to avoid having to
147           duplicate the inherited method definitions there. This time
148           I could have used a trick to use only one macro whatever the
149           number of parameters but I preferred to have it work the same
150           way as above.
151         </para>
152         <para>
153           You probably have noticed that we don't define the fields we
154           need to actually implement this interface: reference count,
155           pointer to other resources and miscellaneous fields. That's
156           because these interfaces are just that: interfaces. They may
157           be implemented more than once, in different contexts and
158           sometimes not even in Wine. Thus it would not make sense to
159           impose that the interface contains some specific fields.
160         </para>
161       </sect2>
162
163       <sect2>
164         <title>Bindings in C</title>
165
166         <para>
167           In C this gives:
168         </para>
169         <programlisting>typedef struct IDirect3DVtbl IDirect3DVtbl;
170 struct IDirect3D {
171     IDirect3DVtbl* lpVtbl;
172 };
173 struct IDirect3DVtbl {
174     HRESULT (*fnQueryInterface)(IDirect3D* me, REFIID riid, LPVOID* ppvObj);
175     ULONG (*fnAddRef)(IDirect3D* me);
176     ULONG (*fnRelease)(IDirect3D* me);
177     HRESULT (*fnInitialize)(IDirect3D* me, REFIID a);
178     HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b);
179     HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b);
180     HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b);
181     HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b);
182     HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b);
183 }; 
184
185 #ifdef ICOM_CINTERFACE
186 // *** IUnknown methods *** //
187 #define IDirect3D_QueryInterface(p,a,b) (p)->lpVtbl->fnQueryInterface(p,a,b)
188 #define IDirect3D_AddRef(p)             (p)->lpVtbl->fnAddRef(p)
189 #define IDirect3D_Release(p)            (p)->lpVtbl->fnRelease(p)
190 // *** IDirect3D methods *** //
191 #define IDirect3D_Initialize(p,a)       (p)->lpVtbl->fnInitialize(p,a)
192 #define IDirect3D_EnumDevices(p,a,b)    (p)->lpVtbl->fnEnumDevice(p,a,b)
193 #define IDirect3D_CreateLight(p,a,b)    (p)->lpVtbl->fnCreateLight(p,a,b)
194 #define IDirect3D_CreateMaterial(p,a,b) (p)->lpVtbl->fnCreateMaterial(p,a,b)
195 #define IDirect3D_CreateViewport(p,a,b) (p)->lpVtbl->fnCreateViewport(p,a,b)
196 #define IDirect3D_FindDevice(p,a,b)     (p)->lpVtbl->fnFindDevice(p,a,b)
197 #endif</programlisting>
198         <para>
199           Comments:
200         </para>
201         <para>
202           IDirect3D only contains a pointer to the IDirect3D
203           virtual/jump table. This is the only thing the user needs to
204           know to use the interface. Of course the structure we will
205           define to implement this interface will have more fields but
206           the first one will match this pointer.
207         </para>
208         <para>
209           The code generated by ICOM_DEFINE defines both the structure
210           representing the interface and the structure for the jump
211           table. ICOM_DEFINE uses the parent's Xxx_IMETHODS macro to
212           automatically repeat the prototypes of all the inherited
213           methods and then uses IDirect3D_METHODS to define the
214           IDirect3D methods.
215         </para>
216         <para>
217           Each method is declared as a pointer to function field in
218           the jump table. The implementation will fill this jump table
219           with appropriate values, probably using a static variable,
220           and initialize the lpVtbl field to point to this variable.
221         </para>
222         <para>
223           The IDirect3D_Xxx macros then just dereference the lpVtbl
224           pointer and use the function pointer corresponding to the
225           macro name. This emulates the behavior of a virtual table
226           and should be just as fast.
227         </para>
228         <para>
229           This C code should be quite compatible with the Windows
230           headers both for code that uses COM interfaces and for code
231           implementing a COM interface.
232         </para>
233       </sect2>
234
235       <sect2>
236         <title>Bindings in C++</title>
237         <para>
238           And in C++ (with gcc's g++):
239         </para>
240         <programlisting>typedef struct IDirect3D: public IUnknown {
241     private: HRESULT (*fnInitialize)(IDirect3D* me, REFIID a);
242     public: inline HRESULT Initialize(REFIID a) { return ((IDirect3D*)t.lpVtbl)->fnInitialize(this,a); };
243     private: HRESULT (*fnEnumDevices)(IDirect3D* me, LPD3DENUMDEVICESCALLBACK a, LPVOID b);
244     public: inline HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK a, LPVOID b)
245         { return ((IDirect3D*)t.lpVtbl)->fnEnumDevices(this,a,b); };
246     private: HRESULT (*fnCreateLight)(IDirect3D* me, LPDIRECT3DLIGHT* a, IUnknown* b);
247     public: inline HRESULT CreateLight(LPDIRECT3DLIGHT* a, IUnknown* b)
248         { return ((IDirect3D*)t.lpVtbl)->fnCreateLight(this,a,b); };
249     private: HRESULT (*fnCreateMaterial)(IDirect3D* me, LPDIRECT3DMATERIAL* a, IUnknown* b);
250     public: inline HRESULT CreateMaterial(LPDIRECT3DMATERIAL* a, IUnknown* b)
251         { return ((IDirect3D*)t.lpVtbl)->fnCreateMaterial(this,a,b); };
252     private: HRESULT (*fnCreateViewport)(IDirect3D* me, LPDIRECT3DVIEWPORT* a, IUnknown* b);
253     public: inline HRESULT CreateViewport(LPDIRECT3DVIEWPORT* a, IUnknown* b)
254         { return ((IDirect3D*)t.lpVtbl)->fnCreateViewport(this,a,b); };
255     private:  HRESULT (*fnFindDevice)(IDirect3D* me, LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b);
256     public: inline HRESULT FindDevice(LPD3DFINDDEVICESEARCH a, LPD3DFINDDEVICERESULT b)
257         { return ((IDirect3D*)t.lpVtbl)->fnFindDevice(this,a,b); };
258 };</programlisting>
259         <para>
260           Comments:
261         </para>
262         <para>
263           In C++ IDirect3D does double duty as both the virtual/jump
264           table and as the interface definition. The reason for this
265           is to avoid having to duplicate the method definitions: once
266           to have the function pointers in the jump table and once to
267           have the methods in the interface class. Here one macro can
268           generate both. This means though that the first pointer,
269           t.lpVtbl defined in IUnknown, must be interpreted as the
270           jump table pointer if we interpret the structure as the
271           interface class, and as the function pointer to the
272           QueryInterface method, t.fnQueryInterface, if we interpret
273           the structure as the jump table. Fortunately this gymnastic
274           is entirely taken care of in the header of IUnknown.
275         </para>
276         <para>
277           Of course in C++ we use inheritance so that we don't have to
278           duplicate the method definitions.
279         </para>
280         <para>
281           Since IDirect3D does double duty, each ICOM_METHOD macro
282           defines both a function pointer and a non-virtual inline
283           method which dereferences it and calls it. This way this
284           method behaves just like a virtual method but does not
285           create a true C++ virtual table which would break the
286           structure layout. If you look at the implementation of these
287           methods you'll notice that they would not work for void
288           functions. We have to return something and fortunately this
289           seems to be what all the COM methods do (otherwise we would
290           need another set of macros).
291         </para>
292         <para>
293           Note how the ICOM_METHOD generates both function prototypes
294           mixing types and formal parameter names and the method
295           invocation using only the formal parameter name. This is the
296           reason why we need different macros to handle different
297           numbers of parameters.
298         </para>
299         <para>
300           Finally there is no IDirect3D_Xxx macro. These are not
301           needed in C++ unless the CINTERFACE macro is defined in
302           which case we would not be here.
303         </para>
304         <para>
305           This C++ code works well for code that just uses COM
306           interfaces. But it will not work with C++ code implement a
307           COM interface. That's because such code assumes the
308           interface methods are declared as virtual C++ methods which
309           is not the case here.
310         </para>
311       </sect2>
312
313       <sect2>
314         <title>Implementing a COM interface.</title>
315
316         <para>
317           This continues the above example. This example assumes that
318           the implementation is in C.
319         </para>
320         <programlisting>typedef struct _IDirect3D {
321     void* lpVtbl;
322     // ...
323  } _IDirect3D;
324
325 static ICOM_VTABLE(IDirect3D) d3dvt;
326
327 // implement the IDirect3D methods here
328
329 int IDirect3D_fnQueryInterface(IDirect3D* me)
330 {
331     ICOM_THIS(IDirect3D,me);
332     // ...
333 }
334
335 // ...
336
337 static ICOM_VTABLE(IDirect3D) d3dvt = {
338     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
339     IDirect3D_fnQueryInterface,
340     IDirect3D_fnAdd,
341     IDirect3D_fnAdd2,
342     IDirect3D_fnInitialize,
343     IDirect3D_fnSetWidth
344 };</programlisting>
345         <para>
346           Comments:
347         </para>
348         <para>
349           We first define what the interface really contains. This is
350           the _IDirect3D structure. The first field must of course be
351           the virtual table pointer. Everything else is free.
352         </para>
353         <para>
354           Then we predeclare our static virtual table variable, we
355           will need its address in some methods to initialize the
356           virtual table pointer of the returned interface objects.
357         </para>
358         <para>
359           Then we implement the interface methods. To match what has
360           been declared in the header file they must take a pointer to
361           a IDirect3D structure and we must cast it to an _IDirect3D
362           so that we can manipulate the fields. This is performed by
363           the ICOM_THIS macro.
364         </para>
365         <para>
366           Finally we initialize the virtual table.
367         </para>
368       </sect2>
369     </sect1>
370                                          
371     <sect1 id="dcom-1">
372       <title>A brief introduction to DCOM in Wine</title>
373
374       <para>
375         This section explains the basic principles behind DCOM remoting as used by InstallShield and others.
376       </para>
377
378       <sect2>
379         <title>BASICS</title>
380
381         <para>
382           The basic idea behind DCOM is to take a COM object and make it location
383           transparent. That means you can use it from other threads, processes and
384           machines without having to worry about the fact that you can't just
385           dereference the interface vtable pointer to call methods on it.
386         </para>
387
388         <para>
389           You might be wondering about putting threads next to processes and
390           machines in that last paragraph. You can access thread safe objects from
391           multiple threads without DCOM normally, right? Why would you need RPC
392           magic to do that?
393         </para>
394
395         <para>
396           The answer is of course that COM doesn't assume that objects actually
397           are thread-safe. Most real-world objects aren't, in fact, for various
398           reasons. What these reasons are isn't too important here, though, it's
399           just important to realize that the problem of thread-unsafe objects is
400           what COM tries hard to solve with its apartment model. There are also
401           ways to tell COM that your object is truly thread-safe (namely the
402           free-threaded marshaller). In general, no object is truly thread-safe if
403           it could potentially use another not so thread-safe object, though, so
404           the free-threaded marshaller is less used than you'd think.
405         </para>
406         
407         <para>
408           For now, suffice it to say that COM lets you "marshal" interfaces into
409           other "apartments". An apartment (you may see it referred to as a
410           context in modern versions of COM) can be thought of as a location, and
411           contains objects. 
412         </para>
413
414         <para>
415           Every thread in a program that uses COM exists in an apartment. If a
416           thread wishes to use an object from another apartment, marshalling and
417           the whole DCOM infrastructure gets involved to make that happen behind
418           the scenes.
419         </para>
420
421         <para>
422           So. Each COM object resides in an apartment, and each apartment
423           resides in a process, and each process resides in a machine, and each
424           machine resides in a network. Allowing those objects to be used
425           from <emphasis>any</emphasis> of these different places is what DCOM
426           is all about.
427         </para>
428
429         <para>
430           The process of marshalling refers to taking a function call in an
431           apartment and actually performing it in another apartment. Let's say you
432           have two machines, A and B, and on machine B there is an object sitting
433           in a DLL on the hard disk. You want to create an instance of that object
434           (activate it) and use it as if you had compiled it into your own
435           program. This is hard, because the remote object is expecting to be
436           called by code in its own address space - it may do things like accept
437           pointers to linked lists and even return other objects.
438         </para>
439
440         <para>
441           Very basic marshalling is easy enough to understand. You take a method
442           on a remote interface, copy each of its parameters into a buffer, and
443           send it to the remote computer. On the other end, the remote server
444           reads each parameter from the buffer, calls the method, writes the
445           result into another buffer and sends it back.
446         </para>
447
448         <para>
449           The tricky part is exactly how to encode those parameters in the buffer,
450           and how to convert standard stdcall/cdecl method calls to network
451           packets and back again. This is the job of the RPCRT4.DLL file - or the
452           Remote Procedure Call Runtime. 
453         </para>
454
455         <para>
456           The backbone of DCOM is this RPC runtime, which is an implementation
457           of <ulink
458           url="http://www.opengroup.org/onlinepubs/009629399/toc.htm">DCE
459           RPC</ulink>. DCE RPC is not naturally object oriented, so this
460           protocol is extended with some new constructs and by assigning new
461           meanings to some of the packet fields, to produce ORPC or Object
462           RPC. You might see it called MS-RPC as well.
463         </para>
464
465         <para>
466           RPC packets contain a buffer containing marshalled data in NDR format.
467           NDR is short for "Network Data Representation" and is similar the XDR
468           format used in SunRPC (the closest native equivalent on Linux to DCE
469           RPC). NDR/XDR are all based on the idea of graph serialization and were
470           worked out during the 80s, meaning they are very powerful and can do
471           things like marshal doubly linked lists and other rather tricky
472           structures.
473         </para>
474
475         <para>
476           In Wine, our DCOM implementation is <emphasis>not</emphasis> based on the
477           RPC runtime, as while few programs use DCOM even fewer use
478           RPC directly so it was developed some time after
479           OLE32/OLEAUT32 were. Eventually this will have to be fixed,
480           otherwise our DCOM will never be compatible with
481           Microsofts. Bear this in mind as you read through the code
482           however.
483         </para>
484       </sect2>
485       
486       <sect2>
487         <title>PROXIES AND STUBS</title>
488
489         <para>
490           Manually marshalling and unmarshalling each method call using the NDR
491           APIs (NdrConformantArrayMarshall etc) is very tedious work, so the
492           Platform SDK ships with a tool called "midl" which is an IDL compiler.
493           IDL or the "Interface Definition Language" is a tool designed
494           specifically for describing interfaces in a reasonably language neutral
495           fashion, though in reality it bears a close resemblence to C++.
496         </para>
497
498         <para>
499           By describing the functions you want to expose via RPC in IDL therefore,
500           it becomes possible to pass this file to MIDL which spits out a huge
501           amount of C source code. That code defines functions which have the same
502           prototype as the functions described in your IDL but which internally
503           take each argument, marshal it using Ndr, send the packet, and unmarshal
504           the return.
505         </para>
506         
507         <para>
508           Because this code proxies the code from the client to the server, the
509           functions are called proxies. Easy, right?
510         </para>
511
512         <para>
513           Of course, in the RPC server process at the other end, you need some way
514           to unmarshal the RPCs, so you have functions also generated by MIDL
515           which are the inverse of the proxies: they accept an NDR buffer, extract
516           the parameters, call the real function then marshal the result back.
517           They are called stubs, and stand in for the real calling code in the
518           client process.
519         </para>
520         
521         <para>
522           The sort of marshalling/unmarshalling code that MIDL spits out can be
523           seen in dlls/oleaut32/oaidl_p.c - it's not exactly what it would look
524           like as that file contains DCOM proxies/stubs which are different, but
525           you get the idea. Proxy functions take the arguments and feel them to
526           the NDR marshallers (or picklers), invoke an NdrProxySendReceive and
527           then convert the out parameters and return code. There's a ton of goop
528           in there for dealing with buffer allocation, exceptions and so on - it's
529           really ugly code. But, this is the basic concept behind DCE RPC.
530         </para>
531       </sect2>
532       
533       <sect2>
534         <title>INTERFACE MARSHALLING</title>
535
536         <para>
537           Standard NDR only knows about C style function calls - they
538           can accept and even return structures, but it has no concept
539           of COM interfaces.  Confusingly DCE RPC <emphasis>does</emphasis> have a
540           concept of RPC interfaces which are just convenient ways to
541           bundle function calls together into namespaces, but let's
542           ignore that for now as it just muddies the water. The
543           primary extension made by Microsoft to NDR then was the
544           ability to take a COM interface pointer and marshal that
545           into the NDR stream.
546         </para>
547
548         <para>
549           The basic theory of proxies and stubs and IDL is still here, but it's
550           been modified slightly. Whereas before you could define a bunch of
551           functions in IDL, now a new "object" keyword has appeared. This tells
552           MIDL that you're describing a COM interface, and as a result the
553           proxies/stubs it generates are also COM objects.
554         </para>
555
556         <para>
557           That's a very important distinction. When you make a call to a remote
558           COM object you do it via a proxy object that COM has constructed on the
559           fly. Likewise, a stub object on the remote end unpacks the RPC packet
560           and makes the call. 
561         </para>
562
563         <para>
564           Because this is object-oriented RPC, there are a few complications: for
565           instance, a call that goes via the same proxies/stubs may end up at a
566           different object instance, so the RPC runtime keeps track of "this" and
567           "that" in the RPC packets.
568         </para>
569
570         <para>
571           This leads naturally onto the question of how we got those proxy/stub
572           objects in the first place, and where they came from. You can use the
573           CoCreateInstanceEx API to activate COM objects on a remote machine, this
574           works like CoCreateInstance API. Behind the scenes, a lot of stuff is
575           involved to do this (like IRemoteActivation, IOXIDResolver and so on)
576           but let's gloss over that for now.
577         </para>
578
579         <para>
580           When DCOM creates an object on a remote machine, the DCOM runtime on
581           that machine activates the object in the usual way (by looking it up in
582           the registry etc) and then marshals the requested interface back to the
583           client. Marshalling an interface takes a pointer, and produces a buffer
584           containing all the information DCOM needs to construct a proxy object in
585           the client, a stub object in the server and link the two together.
586         </para>
587
588         <para>
589           The structure of a marshalled interface pointer is somewhat complex.
590           Let's ignore that too. The important thing is how COM proxies/stubs are
591           loaded.
592         </para>
593       </sect2>
594
595       <sect2>
596         <title>COM PROXY/STUB SYSTEM</title>
597
598         <para>
599           COM proxies are objects that implement both the interfaces needing to be
600           proxied and also IRpcProxyBuffer. Likewise, COM stubs implement
601           IRpcStubBuffer and understand how to invoke the methods of the requested
602           interface.
603         </para>
604
605         <para>
606           You may be wondering what the word "buffer" is doing in those interface
607           names. I'm not sure either, except that a running theme in DCOM is that
608           interfaces which have nothing to do with buffers have the word Buffer
609           appended to them, seemingly at random. Ignore it and <emphasis>don't let it
610             confuse you</emphasis>
611           :) This stuff is convoluted enough ...
612         </para>
613
614         <para>
615           The IRpc[Proxy/Stub]Buffer interfaces are used to control the proxy/stub
616           objects and are one of the many semi-public interfaces used in DCOM.
617         </para>
618
619         <para>
620           DCOM is theoretically an internet RFC <ulink
621                                                    url="http://www.grimes.demon.co.uk/DCOM/DCOMSpec.htm">[2]</ulink> and is
622           specced out, but in reality the only implementation of it apart from
623           ours is Microsofts, and as a result there are lots of interfaces
624           which <emphasis>can</emphasis> be used if you want to customize or
625           control DCOM but in practice are badly documented or not documented at
626           all, or exist mostly as interfaces between MIDL generated code and COM
627           itself. Don't pay too much attention to the MSDN definitions of these
628           interfaces and APIs.
629         </para>
630
631         <para>
632           COM proxies and stubs are like any other normal COM object - they are
633           registered in the registry, they can be loaded with CoCreateInstance and
634           so on. They have to be in process (in DLLs) however. They aren't
635           activated directly by COM however, instead the process goes something
636           like this:
637           
638           <itemizedlist>
639             <listitem> <para> COM receives a marshalled interface packet, and retrieves the IID of
640                 the marshalled interface from it </para> </listitem>
641
642
643             <listitem> <para> COM looks in
644               HKEY_CLASSES_ROOT/Interface/{whatever-iid}/ProxyStubClsId32
645               to retrieve the CLSID of another COM object, which
646               implements IPSFactoryBuffer. </para> </listitem>
647             
648             <listitem> <para> IPSFactoryBuffer has only two methods, CreateProxy and CreateStub. COM
649                 calls whichever is appropriate: CreateStub for the server, CreateProxy
650                 for the client. MIDL will normally provide an implementation of this
651                 object for you in the code it generates. </para></listitem>
652           </itemizedlist>
653           
654         </para>
655
656         <para>
657           Once CreateProxy has been called, the resultant object is QueryInterfaced to
658           IRpcProxyBuffer, which only has 1 method, IRpcProxyBuffer::Connect.
659           This method only takes one parameter, the IRpcChannelBuffer object which
660           encapsulates the "RPC Channel" between the client and server.
661         </para>
662
663         <para>
664           On the server side, a similar process is performed - the PSFactoryBuffer
665           is created, CreateStub is called, result is QId to IRpcStubBuffer, and
666           IRpcStubBuffer::Connect is used to link it to the RPC channel.
667         </para>
668
669       </sect2>
670
671       <sect2>
672         <title>RPC CHANNELS</title>
673
674         <para>
675           Remember the RPC runtime? Well, that's not just responsible for
676           marshalling stuff, it also controls the connection and protocols between
677           the client and server. We can ignore the details of this for now,
678           suffice it to say that an RPC Channel is a COM object that implements
679           IRpcChannelBuffer, and it's basically an abstraction of different RPC
680           methods. For instance, in the case of inter-thread marshalling (not
681           covered here) the RPC connection code isn't used, only the NDR
682           marshallers are, so IRpcChannelBuffer in that case isn't actually
683           implemented by RPCRT4 but rather just by the COM/OLE DLLS.
684         </para>
685
686         <para>
687           On this topic, Ove Kaaven says: It depends on the Windows version, I
688           think. Windows 95 and Windows NT 4 certainly had very different models
689           when I looked. I'm pretty sure the Windows 98 version of RPCRT4 was
690           able to dispatch messages directly to individual apartments. I'd be
691           surprised if some similar functionality was not added to Windows
692           2000. After all, if an object on machine A wanted to use an object on
693           machine B in an apartment C, wouldn't it be most efficient if the RPC
694           system knew about apartments and could dispatch the message directly
695           to it? And if RPC does know how to efficiently dispatch to apartments,
696           why should COM duplicate this functionality? There were, however, no
697           unified way to tell RPC about them across Windows versions, so in that
698           old patch of mine, I let the COM/OLE dlls do the apartment dispatch,
699           but even then, the RPC runtime was always involved. After all, it
700           could be quite tricky to tell whether the call is merely interthread,
701           without involving the RPC runtime...
702         </para>
703
704         <para>
705           RPC channels are constructed on the fly by DCOM as part of the
706           marshalling process. So, when you make a call on a COM proxy, it goes
707           like this:
708         </para>
709
710         <para>
711           Your code -&gt; COM proxy object -&gt; RPC Channel -&gt; COM stub object -&gt; Their code
712         </para>
713
714       </sect2>
715
716       <sect2>
717         <title>HOW THIS ACTUALLY WORKS IN WINE</title>
718
719         <para>
720           Right now, Wine does not use the NDR marshallers or RPC to implement its
721           DCOM. When you marshal an interface in Wine, in the server process a
722           _StubMgrThread thread is started. I haven't gone into the stub manager
723           here. The important thing is that eventually a _StubReaderThread is
724           started which accepts marshalled DCOM RPCs, and then passes them to
725           IRpcStubBuffer::Invoke on the correct stub object which in turn
726           demarshals the packet and performs the call. The threads started by our
727           implementation of DCOM are never terminated, they just hang around until
728           the process dies.
729         </para>
730
731         <para>
732           Remember that I said our DCOM doesn't use RPC? Well, you might be
733           thinking "but we use IRpcStubBuffer like we're supposed to ... isn't
734           that provided by MIDL which generates code that uses the NDR APIs?". If
735           so pat yourself on the back, you're still with me. Go get a cup of
736           coffee.
737         </para>
738
739       </sect2>
740
741       <sect2>
742         <title>TYPELIB MARSHALLER</title>
743
744         <para>
745           In fact, the reason for the PSFactoryBuffer layer of indirection is
746           because you not all interfaces are marshalled using MIDL generated code.
747           Why not? Well, to understand <emphasis>that</emphasis>
748           you have to see that one of the
749           driving forces behind OLE and by extension DCOM was the development
750           Visual Basic. Microsoft wanted VB developers to be first class citizens
751           in the COM world, but things like writing IDL and compiling them with a
752           C compiler into DLLs wasn't easy enough.
753         </para>
754
755         <para>
756           So, type libraries were invented. Actually they were invented as part of
757           a parallel line of COM development known as "OLE Automation", but let's
758           not get into that here. Type libraries are basically binary IDL files,
759           except that despite there being two type library formats neither of them
760           can fully express everything expressable in IDL. Anyway, with a type
761           library (which can be embedded as a resource into a DLL) you have
762           another option beyond compiling MIDL output - you can set the
763           ProxyStubClsId32 registry entry for your interfaces to the CLSID of the
764           "type library marshaller" or "universal marshaller". Both terms are
765           used, but in the Wine source it's called the typelib marshaller.
766         </para>
767
768         <para>
769           The type library marshaller constructs proxy and stub objects on the
770           fly. It does so by having generic marshalling glue which reads the
771           information from the type libraries, and takes the parameters directly
772           off the stack. The CreateProxy method actually builds a vtable out of
773           blocks of assembly stitched together which pass control to _xCall, which
774           then does the marshalling. You can see all this magic in
775           dlls/oleaut32/tmarshal.c
776         </para>
777
778         <para>
779           In the case of InstallShield, it actually comes with typelibs for all
780           the interfaces it needs to marshal (fixme: is this right?), but they
781           actually use a mix of MIDL and typelib marshalling. In order to cover up
782           for the fact that we don't really use RPC they're all force to go via
783           the typelib marshaller - that's what the 1 || hack is for and what the
784           "Registering non-automation type library!" warning is about (I think).
785         </para>
786       </sect2>
787
788       <sect2>
789         <title>WRAPUP</title>
790
791         <para>
792           OK, so there are some (very) basic notes on DCOM. There's a ton of stuff
793           I have not covered:
794         </para>
795         
796         <itemizedlist>
797           <listitem><para> Format strings/MOPs</para></listitem>
798           
799           <listitem><para> Apartments, threading models, inter-thread marshalling</para></listitem>
800           
801           <listitem><para> OXIDs/OIDs, etc, IOXIDResolver</para></listitem>
802           
803           <listitem><para> IRemoteActivation</para></listitem>
804           
805           <listitem><para> Complex/simple pings, distributed garbage collection</para></listitem>
806
807           <listitem><para> Marshalling IDispatch</para></listitem>
808           
809           <listitem><para> Structure of marshalled interface pointers (STDOBJREFs etc)</para></listitem>
810           
811           <listitem><para> Runtime class object registration (CoRegisterClassObject), ROT</para></listitem>
812           
813           <listitem><para> IRemUnknown</para></listitem>
814           
815           <listitem><para> Exactly how InstallShield uses DCOM</para></listitem>
816         </itemizedlist>
817
818         <para>
819           Then there's a bunch of stuff I still don't understand, like ICallFrame,
820           interface pointer swizzling, exactly where and how all this stuff is
821           actually implemented and so on.
822         </para>
823
824         <para>
825           But for now that's enough.
826         </para>
827       </sect2>
828
829       <sect2>
830         <title>FURTHER READING</title>
831
832         <para>
833           Most of these documents assume you have knowledge only contained in
834           other documents. You may have to reread them a few times for it all to
835           make sense. Don't feel you need to read these to understand DCOM, you
836           don't, you only need to look at them if you're planning to help
837           implement it.
838         </para>
839
840         <itemizedlist>
841             <listitem><para>
842               <ulink url="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmi_n2p_459u.asp">
843                 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmi_n2p_459u.asp</ulink>
844
845             </para></listitem>
846
847
848             <listitem><para>
849               <ulink url="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmi_q2z_5ygi.asp">
850                 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmi_q2z_5ygi.asp</ulink>
851             </para></listitem>
852
853
854             <listitem><para>
855                 <ulink url="http://www.microsoft.com/msj/0398/dcom.aspx">
856                   http://www.microsoft.com/msj/0398/dcom.aspx</ulink>
857             </para></listitem>
858
859             <listitem><para>
860                 <ulink url="http://www.microsoft.com/ntserver/techresources/appserv/COM/DCOM/4_ConnectionMgmt.asp">
861                   http://www.microsoft.com/ntserver/techresources/appserv/COM/DCOM/4_ConnectionMgmt.asp</ulink>
862             </para></listitem>
863
864
865             <listitem><para><ulink url="http://www.idevresource.com/com/library/articles/comonlinux.asp">
866                   http://www.idevresource.com/com/library/articles/comonlinux.asp</ulink>
867
868                 (unfortunately part 2 of this article does not seem to exist anymore, if it was ever written)</para></listitem>
869         </itemizedlist>
870       </sect2>
871     </sect1>
872   </chapter>
873
874 <!-- Keep this comment at the end of the file
875 Local variables:
876 mode: sgml
877 sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "")
878 End:
879 -->