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