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