Fix subclassing to support nested messages.
[wine] / dlls / ole32 / marshal.c
1 /*
2  *      Marshalling library
3  *
4  *  Copyright 2002  Marcus Meissner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "objbase.h"
33 #include "ole2.h"
34 #include "ole2ver.h"
35 #include "rpc.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wownt32.h"
39 #include "wtypes.h"
40 #include "wine/unicode.h"
41 #include "wine/winbase16.h"
42 #include "compobj_private.h"
43 #include "ifs.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ole);
48
49 extern const CLSID CLSID_DfMarshal;
50
51 /* Marshalling just passes a unique identifier to the remote client,
52  * that makes it possible to find the passed interface again.
53  *
54  * So basically we need a set of values that make it unique.
55  *
56  *      Process Identifier, Object IUnknown ptr, IID
57  *
58  * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
59  */
60
61 typedef struct _mid2unknown {
62     wine_marshal_id     mid;
63     LPUNKNOWN           pUnk;
64 } mid2unknown;
65
66 typedef struct _mid2stub {
67     wine_marshal_id     mid;
68     IRpcStubBuffer      *stub;
69     LPUNKNOWN           pUnkServer;
70 } mid2stub;
71
72 static mid2stub *stubs = NULL;
73 static int nrofstubs = 0;
74
75 static mid2unknown *proxies = NULL;
76 static int nrofproxies = 0;
77
78 HRESULT
79 MARSHAL_Find_Stub_Server(wine_marshal_id *mid,LPUNKNOWN *punk) {
80     int i;
81
82     for (i=0;i<nrofstubs;i++) {
83         if (MARSHAL_Compare_Mids_NoInterface(mid,&(stubs[i].mid))) {
84             *punk = stubs[i].pUnkServer;
85             IUnknown_AddRef((*punk));
86             return S_OK;
87         }
88     }
89     return E_FAIL;
90 }
91
92 HRESULT
93 MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub) {
94     int i;
95
96     for (i=0;i<nrofstubs;i++) {
97         if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
98             *stub = stubs[i].stub;
99             IUnknown_AddRef((*stub));
100             return S_OK;
101         }
102     }
103     return E_FAIL;
104 }
105
106 HRESULT
107 MARSHAL_Find_Stub(wine_marshal_id *mid,LPUNKNOWN *pUnk) {
108     int i;
109
110     for (i=0;i<nrofstubs;i++) {
111         if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
112             *pUnk = stubs[i].pUnkServer;
113             IUnknown_AddRef((*pUnk));
114             return S_OK;
115         }
116     }
117     return E_FAIL;
118 }
119
120 HRESULT
121 MARSHAL_Register_Stub(wine_marshal_id *mid,LPUNKNOWN pUnk,IRpcStubBuffer *stub) {
122     LPUNKNOWN   xPunk;
123     if (!MARSHAL_Find_Stub(mid,&xPunk)) {
124         FIXME("Already have entry for (%lx/%s)!\n",mid->objectid,debugstr_guid(&(mid->iid)));
125         return S_OK;
126     }
127     if (nrofstubs)
128         stubs=HeapReAlloc(GetProcessHeap(),0,stubs,sizeof(stubs[0])*(nrofstubs+1));
129     else
130         stubs=HeapAlloc(GetProcessHeap(),0,sizeof(stubs[0]));
131     if (!stubs) return E_OUTOFMEMORY;
132     stubs[nrofstubs].stub = stub;
133     stubs[nrofstubs].pUnkServer = pUnk;
134     memcpy(&(stubs[nrofstubs].mid),mid,sizeof(*mid));
135     nrofstubs++;
136     return S_OK;
137 }
138
139 HRESULT
140 MARSHAL_Find_Proxy(wine_marshal_id *mid,LPUNKNOWN *punk) {
141     int i;
142
143     for (i=0;i<nrofproxies;i++)
144         if (MARSHAL_Compare_Mids(mid,&(proxies[i].mid))) {
145             *punk = proxies[i].pUnk;
146             IUnknown_AddRef((*punk));
147             return S_OK;
148         }
149     return E_FAIL;
150 }
151
152 HRESULT
153 MARSHAL_Find_Proxy_Object(wine_marshal_id *mid,LPUNKNOWN *punk) {
154     int i;
155
156     for (i=0;i<nrofproxies;i++)
157         if (MARSHAL_Compare_Mids_NoInterface(mid,&(proxies[i].mid))) {
158             *punk = proxies[i].pUnk;
159             IUnknown_AddRef((*punk));
160             return S_OK;
161         }
162     return E_FAIL;
163 }
164
165 HRESULT
166 MARSHAL_Register_Proxy(wine_marshal_id *mid,LPUNKNOWN punk) {
167     int i;
168
169     for (i=0;i<nrofproxies;i++) {
170         if (MARSHAL_Compare_Mids(mid,&(proxies[i].mid))) {
171             ERR("Already have mid?\n");
172             return E_FAIL;
173         }
174     }
175     if (nrofproxies)
176         proxies = HeapReAlloc(GetProcessHeap(),0,proxies,sizeof(proxies[0])*(nrofproxies+1));
177     else
178         proxies = HeapAlloc(GetProcessHeap(),0,sizeof(proxies[0]));
179     memcpy(&(proxies[nrofproxies].mid),mid,sizeof(*mid));
180     proxies[nrofproxies].pUnk = punk;
181     nrofproxies++;
182     IUnknown_AddRef(punk);
183     return S_OK;
184 }
185
186 /********************** StdMarshal implementation ****************************/
187 typedef struct _StdMarshalImpl {
188   ICOM_VTABLE(IMarshal) *lpvtbl;
189   DWORD                 ref;
190
191   IID                   iid;
192   DWORD                 dwDestContext;
193   LPVOID                pvDestContext;
194   DWORD                 mshlflags;
195 } StdMarshalImpl;
196
197 HRESULT WINAPI
198 StdMarshalImpl_QueryInterface(LPMARSHAL iface,REFIID riid,LPVOID *ppv) {
199   *ppv = NULL;
200   if (IsEqualIID(&IID_IUnknown,riid) || IsEqualIID(&IID_IMarshal,riid)) {
201     *ppv = iface;
202     IUnknown_AddRef(iface);
203     return S_OK;
204   }
205   FIXME("No interface for %s.\n",debugstr_guid(riid));
206   return E_NOINTERFACE;
207 }
208
209 ULONG WINAPI
210 StdMarshalImpl_AddRef(LPMARSHAL iface) {
211   ICOM_THIS(StdMarshalImpl,iface);
212   This->ref++;
213   return This->ref;
214 }
215
216 ULONG WINAPI
217 StdMarshalImpl_Release(LPMARSHAL iface) {
218   ICOM_THIS(StdMarshalImpl,iface);
219   This->ref--;
220
221   if (This->ref)
222     return This->ref;
223   HeapFree(GetProcessHeap(),0,This);
224   return 0;
225 }
226
227 HRESULT WINAPI
228 StdMarshalImpl_GetUnmarshalClass(
229   LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
230   void* pvDestContext, DWORD mshlflags, CLSID* pCid
231 ) {
232   memcpy(pCid,&CLSID_DfMarshal,sizeof(CLSID_DfMarshal));
233   return S_OK;
234 }
235
236 HRESULT WINAPI
237 StdMarshalImpl_GetMarshalSizeMax(
238   LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
239   void* pvDestContext, DWORD mshlflags, DWORD* pSize
240 ) {
241   *pSize = sizeof(wine_marshal_id)+sizeof(wine_marshal_data);
242   return S_OK;
243 }
244
245 HRESULT WINAPI
246 StdMarshalImpl_MarshalInterface(
247   LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
248   void* pvDestContext, DWORD mshlflags
249 ) {
250   wine_marshal_id       mid;
251   wine_marshal_data     md;
252   IUnknown              *pUnk;
253   ULONG                 res;
254   HRESULT               hres;
255   IRpcStubBuffer        *stub;
256   IPSFactoryBuffer      *psfacbuf;
257
258   TRACE("(...,%s,...)\n",debugstr_guid(riid));
259   IUnknown_QueryInterface((LPUNKNOWN)pv,&IID_IUnknown,(LPVOID*)&pUnk);
260   mid.processid = GetCurrentProcessId();
261   mid.objectid = (DWORD)pUnk; /* FIXME */
262   IUnknown_Release(pUnk);
263   memcpy(&mid.iid,riid,sizeof(mid.iid));
264   md.dwDestContext      = dwDestContext;
265   md.mshlflags          = mshlflags;
266   hres = IStream_Write(pStm,&mid,sizeof(mid),&res);
267   if (hres) return hres;
268   hres = IStream_Write(pStm,&md,sizeof(md),&res);
269   if (hres) return hres;
270
271   if (SUCCEEDED(MARSHAL_Find_Stub(&mid,&pUnk))) {
272       IUnknown_Release(pUnk);
273       return S_OK;
274   }
275   hres = get_facbuf_for_iid(riid,&psfacbuf);
276   if (hres) return hres;
277   hres = IPSFactoryBuffer_CreateStub(psfacbuf,riid,pv,&stub);
278   IPSFactoryBuffer_Release(psfacbuf);
279   if (hres) {
280     FIXME("Failed to create a stub for %s\n",debugstr_guid(riid));
281     return hres;
282   }
283   IUnknown_QueryInterface((LPUNKNOWN)pv,riid,(LPVOID*)&pUnk);
284   MARSHAL_Register_Stub(&mid,pUnk,stub);
285   IUnknown_Release(pUnk);
286   return S_OK;
287 }
288
289 HRESULT WINAPI
290 StdMarshalImpl_UnmarshalInterface(
291   LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv
292 ) {
293   wine_marshal_id       mid;
294   wine_marshal_data     md;
295   ULONG                 res;
296   HRESULT               hres;
297   IPSFactoryBuffer      *psfacbuf;
298   IRpcProxyBuffer       *rpcproxy;
299   IRpcChannelBuffer     *chanbuf;
300
301   TRACE("(...,%s,....)\n",debugstr_guid(riid));
302   hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
303   if (hres) return hres;
304   hres = IStream_Read(pStm,&md,sizeof(md),&res);
305   if (hres) return hres;
306   if (SUCCEEDED(MARSHAL_Find_Stub(&mid,(LPUNKNOWN*)ppv))) {
307       FIXME("Calling back to ourselves for %s!\n",debugstr_guid(riid));
308       return S_OK;
309   }
310   hres = get_facbuf_for_iid(riid,&psfacbuf);
311   if (hres) return hres;
312   hres = IPSFactoryBuffer_CreateProxy(psfacbuf,NULL,riid,&rpcproxy,ppv);
313   if (hres) {
314     FIXME("Failed to create a proxy for %s\n",debugstr_guid(riid));
315     return hres;
316   }
317   hres = PIPE_GetNewPipeBuf(&mid,&chanbuf);
318   if (hres) {
319     ERR("Failed to get an rpc channel buffer for %s\n",debugstr_guid(riid));
320   } else {
321     IRpcProxyBuffer_Connect(rpcproxy,chanbuf);
322     IRpcProxyBuffer_Release(rpcproxy); /* no need */
323   }
324   IPSFactoryBuffer_Release(psfacbuf);
325   return hres;
326 }
327
328 HRESULT WINAPI
329 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) {
330   FIXME("(), stub!\n");
331   return S_OK;
332 }
333
334 HRESULT WINAPI
335 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) {
336   FIXME("(), stub!\n");
337   return S_OK;
338 }
339
340 ICOM_VTABLE(IMarshal) stdmvtbl = {
341     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
342     StdMarshalImpl_QueryInterface,
343     StdMarshalImpl_AddRef,
344     StdMarshalImpl_Release,
345     StdMarshalImpl_GetUnmarshalClass,
346     StdMarshalImpl_GetMarshalSizeMax,
347     StdMarshalImpl_MarshalInterface,
348     StdMarshalImpl_UnmarshalInterface,
349     StdMarshalImpl_ReleaseMarshalData,
350     StdMarshalImpl_DisconnectObject
351 };
352
353 /***********************************************************************
354  *              CoGetStandardMarshal    [OLE32.@]
355  *
356  * When the COM library in the client process receives a marshalled
357  * interface pointer, it looks for a CLSID to be used in creating a proxy
358  * for the purposes of unmarshalling the packet. If the packet does not
359  * contain a CLSID for the proxy, COM calls CoGetStandardMarshal, passing a
360  * NULL pUnk value.
361  * This function creates a standard proxy in the client process and returns
362  * a pointer to that proxy's implementation of IMarshal.
363  * COM uses this pointer to call CoUnmarshalInterface to retrieve the pointer
364  * to the requested interface.
365  */
366 HRESULT WINAPI
367 CoGetStandardMarshal(
368   REFIID riid,IUnknown *pUnk,DWORD dwDestContext,LPVOID pvDestContext,
369   DWORD mshlflags, LPMARSHAL *pMarshal
370 ) {
371   StdMarshalImpl *dm;
372
373   if (pUnk == NULL) {
374     FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n",
375       debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,pMarshal
376     );
377     return E_FAIL;
378   }
379   TRACE("(%s,%p,%lx,%p,%lx,%p)\n",
380     debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,pMarshal
381   );
382   dm = (StdMarshalImpl*) *pMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
383   if (!dm) return E_FAIL;
384   dm->lpvtbl            = &stdmvtbl;
385   dm->ref               = 1;
386
387   memcpy(&dm->iid,riid,sizeof(dm->iid));
388   dm->dwDestContext     = dwDestContext;
389   dm->pvDestContext     = pvDestContext;
390   dm->mshlflags         = mshlflags;
391   return S_OK;
392 }
393
394 /* Helper function for getting Marshaler */
395 static HRESULT WINAPI
396 _GetMarshaller(REFIID riid, IUnknown *pUnk,DWORD dwDestContext,
397   void *pvDestContext, DWORD mshlFlags, LPMARSHAL *pMarshal
398 ) {
399   HRESULT hres;
400
401   if (!pUnk)
402       return E_POINTER;
403   hres = IUnknown_QueryInterface(pUnk,&IID_IMarshal,(LPVOID*)pMarshal);
404   if (hres)
405     hres = CoGetStandardMarshal(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,pMarshal);
406   return hres;
407 }
408
409 /***********************************************************************
410  *              CoGetMarshalSizeMax     [OLE32.@]
411  */
412 HRESULT WINAPI
413 CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
414   DWORD dwDestContext, void *pvDestContext, DWORD mshlFlags
415 ) {
416   HRESULT       hres;
417   LPMARSHAL     pMarshal;
418
419   hres = _GetMarshaller(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,&pMarshal);
420   if (hres)
421     return hres;
422   hres = IMarshal_GetMarshalSizeMax(pMarshal,riid,pUnk,dwDestContext,pvDestContext,mshlFlags,pulSize);
423   *pulSize += sizeof(wine_marshal_id)+sizeof(wine_marshal_data)+sizeof(CLSID);
424   IMarshal_Release(pMarshal);
425   return hres;
426 }
427
428
429 /***********************************************************************
430  *              CoMarshalInterface      [OLE32.@]
431  */
432 HRESULT WINAPI
433 CoMarshalInterface( IStream *pStm, REFIID riid, IUnknown *pUnk,
434   DWORD dwDestContext, void *pvDestContext, DWORD mshlflags
435 ) {
436   HRESULT               hres;
437   LPMARSHAL             pMarshal;
438   CLSID                 xclsid;
439   ULONG                 writeres;
440   wine_marshal_id       mid;
441   wine_marshal_data     md;
442   ULONG                 res;
443   IUnknown              *pUnknown;
444
445   TRACE("(%p, %s, %p, %lx, %p, %lx)\n",
446     pStm,debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags
447   );
448   STUBMGR_Start(); /* Just to be sure we have one running. */
449   mid.processid = GetCurrentProcessId();
450   IUnknown_QueryInterface(pUnk,&IID_IUnknown,(LPVOID*)&pUnknown);
451   mid.objectid = (DWORD)pUnknown;
452   IUnknown_Release(pUnknown);
453   memcpy(&mid.iid,riid,sizeof(mid.iid));
454   md.dwDestContext      = dwDestContext;
455   md.mshlflags          = mshlflags;
456   hres = IStream_Write(pStm,&mid,sizeof(mid),&res);
457   if (hres) return hres;
458   hres = IStream_Write(pStm,&md,sizeof(md),&res);
459   if (hres) return hres;
460   hres = _GetMarshaller(riid,pUnk,dwDestContext,pvDestContext,mshlflags,&pMarshal);
461   if (hres) {
462     FIXME("Failed to get marshaller, %lx?\n",hres);
463     return hres;
464   }
465   hres = IMarshal_GetUnmarshalClass(pMarshal,riid,pUnk,dwDestContext,pvDestContext,mshlflags,&xclsid);
466   if (hres) {
467     FIXME("IMarshal:GetUnmarshalClass failed, %lx\n",hres);
468     goto release_marshal;
469   }
470   hres = IStream_Write(pStm,&xclsid,sizeof(xclsid),&writeres);
471   if (hres) {
472     FIXME("Stream write failed, %lx\n",hres);
473     goto release_marshal;
474   }
475   hres = IMarshal_MarshalInterface(pMarshal,pStm,riid,pUnk,dwDestContext,pvDestContext,mshlflags);
476   if (hres) {
477     if (IsEqualGUID(riid,&IID_IClassFactory)) {
478         MESSAGE("\nERROR: You need to merge the 'winedefault.reg' file into your\n");
479         MESSAGE("       Wine registry by running: `regedit winedefault.reg'\n\n");
480     } else {
481         if (IsEqualGUID(riid,&IID_IOleObject)) {
482             ERR("WINE currently cannot marshal IOleObject interfaces. This means you cannot embed/link OLE objects between applications.\n");
483         } else {
484             FIXME("Failed to marshal the interface %s, %lx?\n",debugstr_guid(riid),hres);
485         }
486     }
487     goto release_marshal;
488   }
489 release_marshal:
490   IMarshal_Release(pMarshal);
491   return hres;
492 }
493
494
495 /***********************************************************************
496  *              CoUnmarshalInterface    [OLE32.@]
497  */
498 HRESULT WINAPI
499 CoUnmarshalInterface(IStream *pStm, REFIID riid, LPVOID *ppv) {
500   HRESULT               hres;
501   wine_marshal_id       mid;
502   wine_marshal_data     md;
503   ULONG                 res;
504   LPMARSHAL             pMarshal;
505   LPUNKNOWN             pUnk;
506   CLSID                 xclsid;
507
508   TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(riid),ppv);
509
510   hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
511   if (hres) {
512       FIXME("Stream read 1 failed, %lx, (%ld of %d)\n",hres,res,sizeof(mid));
513       return hres;
514   }
515   hres = IStream_Read(pStm,&md,sizeof(md),&res);
516   if (hres) {
517       FIXME("Stream read 2 failed, %lx, (%ld of %d)\n",hres,res,sizeof(md));
518       return hres;
519   }
520   hres = IStream_Read(pStm,&xclsid,sizeof(xclsid),&res);
521   if (hres) {
522       FIXME("Stream read 3 failed, %lx, (%ld of %d)\n",hres,res,sizeof(xclsid));
523       return hres;
524   }
525   hres=CoCreateInstance(&xclsid,NULL,CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,&IID_IMarshal,(void**)&pUnk);
526   if (hres) {
527       FIXME("Failed to create instance of unmarshaller %s.\n",debugstr_guid(&xclsid));
528       return hres;
529   }
530   hres = _GetMarshaller(riid,pUnk,md.dwDestContext,NULL,md.mshlflags,&pMarshal);
531   if (hres) {
532       FIXME("Failed to get unmarshaller, %lx?\n",hres);
533       return hres;
534   }
535   hres = IMarshal_UnmarshalInterface(pMarshal,pStm,riid,ppv);
536   if (hres) {
537     FIXME("Failed to Unmarshal the interface, %lx?\n",hres);
538     goto release_marshal;
539   }
540 release_marshal:
541   IMarshal_Release(pMarshal);
542   return hres;
543 }
544
545 /***********************************************************************
546  *              CoMarshalInterThreadInterfaceInStream   [OLE32.@]
547  *
548  * Marshal interfaces across threads. We don't have a thread distinction,
549  * meaning most interfaces just work across different threads, the RPC
550  * handles it.
551  */
552 HRESULT WINAPI
553 CoMarshalInterThreadInterfaceInStream(
554   REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm
555 ) {
556   ULONG res;
557   ULARGE_INTEGER        xpos;
558   LARGE_INTEGER         seekto;
559   HRESULT               hres;
560
561   TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
562   hres = CreateStreamOnHGlobal(0, TRUE, ppStm);
563   if (hres) return hres;
564   /* CoMarshalInterface(...); */
565   hres = IStream_Write(*ppStm,&pUnk,sizeof(LPUNKNOWN),&res);
566   if (hres) return hres;
567   memset(&seekto,0,sizeof(seekto));
568   IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos);
569   return S_OK;
570 }
571
572 /***********************************************************************
573  *              CoGetInterfaceAndReleaseStream  [OLE32.@]
574  */
575 HRESULT WINAPI
576 CoGetInterfaceAndReleaseStream(LPSTREAM pStm,REFIID riid, LPVOID *ppv) {
577   ULONG res;
578   HRESULT               hres;
579   LPUNKNOWN             pUnk;
580
581   TRACE("(,%s,)\n",debugstr_guid(riid));
582   /* CoUnmarshalInterface(...); */
583   hres = IStream_Read(pStm,&pUnk,sizeof(LPUNKNOWN),&res);
584   if (hres) return hres;
585   IStream_Release(pStm);
586   return IUnknown_QueryInterface(pUnk,riid,ppv);
587 }
588
589 static HRESULT WINAPI
590 SMCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
591   *ppv = NULL;
592   if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IClassFactory)) {
593     *ppv = (LPVOID)iface;
594     return S_OK;
595   }
596   return E_NOINTERFACE;
597 }
598 static ULONG WINAPI SMCF_AddRef(LPCLASSFACTORY iface) { return 2; }
599 static ULONG WINAPI SMCF_Release(LPCLASSFACTORY iface) { return 1; }
600
601 static HRESULT WINAPI
602 SMCF_CreateInstance(
603   LPCLASSFACTORY iface, LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv
604 ) {
605   if (IsEqualIID(riid,&IID_IMarshal)) {
606       StdMarshalImpl    *dm;
607       dm=(StdMarshalImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
608       if (!dm)
609           return E_FAIL;
610       dm->lpvtbl        = &stdmvtbl;
611       dm->ref           = 1;
612       *ppv = (LPVOID)dm;
613       return S_OK;
614   }
615   FIXME("(%s), not supported.\n",debugstr_guid(riid));
616   return E_NOINTERFACE;
617 }
618
619 static HRESULT WINAPI
620 SMCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) {
621     FIXME("(%d), stub!\n",fLock);
622     return S_OK;
623 }
624
625 static ICOM_VTABLE(IClassFactory) dfmarshalcfvtbl = {
626     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
627     SMCF_QueryInterface,
628     SMCF_AddRef,
629     SMCF_Release,
630     SMCF_CreateInstance,
631     SMCF_LockServer
632 };
633 static ICOM_VTABLE(IClassFactory) *pdfmarshalcfvtbl = &dfmarshalcfvtbl;
634
635 HRESULT
636 MARSHAL_GetStandardMarshalCF(LPVOID *ppv) {
637   *ppv = &pdfmarshalcfvtbl;
638   return S_OK;
639 }