Fix the case of product and company names.
[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 "objbase.h"
32 #include "ole2.h"
33 #include "ole2ver.h"
34 #include "rpc.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "wownt32.h"
38 #include "wtypes.h"
39 #include "wine/unicode.h"
40 #include "wine/winbase16.h"
41 #include "compobj_private.h"
42 #include "ifs.h"
43
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(ole);
47
48 extern const CLSID CLSID_DfMarshal;
49
50 /* Marshalling just passes a unique identifier to the remote client,
51  * that makes it possible to find the passed interface again.
52  *
53  * So basically we need a set of values that make it unique.
54  *
55  *      Process Identifier, Object IUnknown ptr, IID
56  *
57  * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
58  */
59
60 typedef struct _mid2unknown {
61     wine_marshal_id     mid;
62     LPUNKNOWN           pUnk;
63 } mid2unknown;
64
65 typedef struct _mid2stub {
66     wine_marshal_id     mid;
67     IRpcStubBuffer      *stub;
68     LPUNKNOWN           pUnkServer;
69 } mid2stub;
70
71 static mid2stub *stubs = NULL;
72 static int nrofstubs = 0;
73
74 static mid2unknown *proxies = NULL;
75 static int nrofproxies = 0;
76
77 HRESULT
78 MARSHAL_Find_Stub_Server(wine_marshal_id *mid,LPUNKNOWN *punk) {
79     int i;
80
81     for (i=0;i<nrofstubs;i++) {
82         if (MARSHAL_Compare_Mids_NoInterface(mid,&(stubs[i].mid))) {
83             *punk = stubs[i].pUnkServer;
84             IUnknown_AddRef((*punk));
85             return S_OK;
86         }
87     }
88     return E_FAIL;
89 }
90
91 HRESULT
92 MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub) {
93     int i;
94
95     for (i=0;i<nrofstubs;i++) {
96         if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
97             *stub = stubs[i].stub;
98             IUnknown_AddRef((*stub));
99             return S_OK;
100         }
101     }
102     return E_FAIL;
103 }
104
105 HRESULT
106 MARSHAL_Find_Stub(wine_marshal_id *mid,LPUNKNOWN *pUnk) {
107     int i;
108
109     for (i=0;i<nrofstubs;i++) {
110         if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
111             *pUnk = stubs[i].pUnkServer;
112             IUnknown_AddRef((*pUnk));
113             return S_OK;
114         }
115     }
116     return E_FAIL;
117 }
118
119 HRESULT
120 MARSHAL_Register_Stub(wine_marshal_id *mid,LPUNKNOWN pUnk,IRpcStubBuffer *stub) {
121     LPUNKNOWN   xPunk;
122     if (!MARSHAL_Find_Stub(mid,&xPunk)) {
123         FIXME("Already have entry for (%lx/%s)!\n",mid->objectid,debugstr_guid(&(mid->iid)));
124         return S_OK;
125     }
126     if (nrofstubs)
127         stubs=HeapReAlloc(GetProcessHeap(),0,stubs,sizeof(stubs[0])*(nrofstubs+1));
128     else
129         stubs=HeapAlloc(GetProcessHeap(),0,sizeof(stubs[0]));
130     if (!stubs) return E_OUTOFMEMORY;
131     stubs[nrofstubs].stub = stub;
132     stubs[nrofstubs].pUnkServer = pUnk;
133     memcpy(&(stubs[nrofstubs].mid),mid,sizeof(*mid));
134     nrofstubs++;
135     return S_OK;
136 }
137
138 HRESULT
139 MARSHAL_Find_Proxy(wine_marshal_id *mid,LPUNKNOWN *punk) {
140     int i;
141
142     for (i=0;i<nrofproxies;i++)
143         if (MARSHAL_Compare_Mids(mid,&(proxies[i].mid))) {
144             *punk = proxies[i].pUnk;
145             IUnknown_AddRef((*punk));
146             return S_OK;
147         }
148     return E_FAIL;
149 }
150
151 HRESULT
152 MARSHAL_Find_Proxy_Object(wine_marshal_id *mid,LPUNKNOWN *punk) {
153     int i;
154
155     for (i=0;i<nrofproxies;i++)
156         if (MARSHAL_Compare_Mids_NoInterface(mid,&(proxies[i].mid))) {
157             *punk = proxies[i].pUnk;
158             IUnknown_AddRef((*punk));
159             return S_OK;
160         }
161     return E_FAIL;
162 }
163
164 HRESULT
165 MARSHAL_Register_Proxy(wine_marshal_id *mid,LPUNKNOWN punk) {
166     int i;
167
168     for (i=0;i<nrofproxies;i++) {
169         if (MARSHAL_Compare_Mids(mid,&(proxies[i].mid))) {
170             ERR("Already have mid?\n");
171             return E_FAIL;
172         }
173     }
174     if (nrofproxies)
175         proxies = HeapReAlloc(GetProcessHeap(),0,proxies,sizeof(proxies[0])*(nrofproxies+1));
176     else
177         proxies = HeapAlloc(GetProcessHeap(),0,sizeof(proxies[0]));
178     memcpy(&(proxies[nrofproxies].mid),mid,sizeof(*mid));
179     proxies[nrofproxies].pUnk = punk;
180     nrofproxies++;
181     IUnknown_AddRef(punk);
182     return S_OK;
183 }
184
185 /********************** StdMarshal implementation ****************************/
186 typedef struct _StdMarshalImpl {
187   ICOM_VTABLE(IMarshal) *lpvtbl;
188   DWORD                 ref;
189
190   IID                   iid;
191   DWORD                 dwDestContext;
192   LPVOID                pvDestContext;
193   DWORD                 mshlflags;
194 } StdMarshalImpl;
195
196 HRESULT WINAPI
197 StdMarshalImpl_QueryInterface(LPMARSHAL iface,REFIID riid,LPVOID *ppv) {
198   *ppv = NULL;
199   if (IsEqualIID(&IID_IUnknown,riid) || IsEqualIID(&IID_IMarshal,riid)) {
200     *ppv = iface;
201     IUnknown_AddRef(iface);
202     return S_OK;
203   }
204   FIXME("No interface for %s.\n",debugstr_guid(riid));
205   return E_NOINTERFACE;
206 }
207
208 ULONG WINAPI
209 StdMarshalImpl_AddRef(LPMARSHAL iface) {
210   ICOM_THIS(StdMarshalImpl,iface);
211   This->ref++;
212   return This->ref;
213 }
214
215 ULONG WINAPI
216 StdMarshalImpl_Release(LPMARSHAL iface) {
217   ICOM_THIS(StdMarshalImpl,iface);
218   This->ref--;
219
220   if (This->ref)
221     return This->ref;
222   HeapFree(GetProcessHeap(),0,This);
223   return 0;
224 }
225
226 HRESULT WINAPI
227 StdMarshalImpl_GetUnmarshalClass(
228   LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
229   void* pvDestContext, DWORD mshlflags, CLSID* pCid
230 ) {
231   memcpy(pCid,&CLSID_DfMarshal,sizeof(CLSID_DfMarshal));
232   return S_OK;
233 }
234
235 HRESULT WINAPI
236 StdMarshalImpl_GetMarshalSizeMax(
237   LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
238   void* pvDestContext, DWORD mshlflags, DWORD* pSize
239 ) {
240   *pSize = sizeof(wine_marshal_id)+sizeof(wine_marshal_data);
241   return S_OK;
242 }
243
244 HRESULT WINAPI
245 StdMarshalImpl_MarshalInterface(
246   LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
247   void* pvDestContext, DWORD mshlflags
248 ) {
249   wine_marshal_id       mid;
250   wine_marshal_data     md;
251   IUnknown              *pUnk;
252   ULONG                 res;
253   HRESULT               hres;
254   IRpcStubBuffer        *stub;
255   IPSFactoryBuffer      *psfacbuf;
256
257   TRACE("(...,%s,...)\n",debugstr_guid(riid));
258   IUnknown_QueryInterface((LPUNKNOWN)pv,&IID_IUnknown,(LPVOID*)&pUnk);
259   mid.processid = GetCurrentProcessId();
260   mid.objectid = (DWORD)pUnk; /* FIXME */
261   IUnknown_Release(pUnk);
262   memcpy(&mid.iid,riid,sizeof(mid.iid));
263   md.dwDestContext      = dwDestContext;
264   md.mshlflags          = mshlflags;
265   hres = IStream_Write(pStm,&mid,sizeof(mid),&res);
266   if (hres) return hres;
267   hres = IStream_Write(pStm,&md,sizeof(md),&res);
268   if (hres) return hres;
269
270   if (SUCCEEDED(MARSHAL_Find_Stub(&mid,&pUnk))) {
271       IUnknown_Release(pUnk);
272       return S_OK;
273   }
274   hres = get_facbuf_for_iid(riid,&psfacbuf);
275   if (hres) return hres;
276   hres = IPSFactoryBuffer_CreateStub(psfacbuf,riid,pv,&stub);
277   IPSFactoryBuffer_Release(psfacbuf);
278   if (hres) {
279     FIXME("Failed to create a stub for %s\n",debugstr_guid(riid));
280     return hres;
281   }
282   IUnknown_QueryInterface((LPUNKNOWN)pv,riid,(LPVOID*)&pUnk);
283   MARSHAL_Register_Stub(&mid,pUnk,stub);
284   IUnknown_Release(pUnk);
285   return S_OK;
286 }
287
288 HRESULT WINAPI
289 StdMarshalImpl_UnmarshalInterface(
290   LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv
291 ) {
292   wine_marshal_id       mid;
293   wine_marshal_data     md;
294   ULONG                 res;
295   HRESULT               hres;
296   IPSFactoryBuffer      *psfacbuf;
297   IRpcProxyBuffer       *rpcproxy;
298   IRpcChannelBuffer     *chanbuf;
299
300   TRACE("(...,%s,....)\n",debugstr_guid(riid));
301   hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
302   if (hres) return hres;
303   hres = IStream_Read(pStm,&md,sizeof(md),&res);
304   if (hres) return hres;
305   if (SUCCEEDED(MARSHAL_Find_Stub(&mid,(LPUNKNOWN*)ppv))) {
306       FIXME("Calling back to ourselves for %s!\n",debugstr_guid(riid));
307       return S_OK;
308   }
309   hres = get_facbuf_for_iid(riid,&psfacbuf);
310   if (hres) return hres;
311   hres = IPSFactoryBuffer_CreateProxy(psfacbuf,NULL,riid,&rpcproxy,ppv);
312   if (hres) {
313     FIXME("Failed to create a proxy for %s\n",debugstr_guid(riid));
314     return hres;
315   }
316   hres = PIPE_GetNewPipeBuf(&mid,&chanbuf);
317   if (hres) {
318     ERR("Failed to get an rpc channel buffer for %s\n",debugstr_guid(riid));
319   } else {
320     IRpcProxyBuffer_Connect(rpcproxy,chanbuf);
321     IRpcProxyBuffer_Release(rpcproxy); /* no need */
322   }
323   IPSFactoryBuffer_Release(psfacbuf);
324   return hres;
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 marshalled
356  * interface pointer, it looks for a CLSID to be used in creating a proxy
357  * for the purposes of unmarshalling 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         if (IsEqualGUID(riid,&IID_IOleObject)) {
481             ERR("WINE currently cannot marshal IOleObject interfaces. This means you cannot embed/link OLE objects between applications.\n");
482         } else {
483             FIXME("Failed to marshal the interface %s, %lx?\n",debugstr_guid(riid),hres);
484         }
485     }
486     goto release_marshal;
487   }
488 release_marshal:
489   IMarshal_Release(pMarshal);
490   return hres;
491 }
492
493
494 /***********************************************************************
495  *              CoUnmarshalInterface    [OLE32.50]
496  */
497 HRESULT WINAPI
498 CoUnmarshalInterface(IStream *pStm, REFIID riid, LPVOID *ppv) {
499   HRESULT               hres;
500   wine_marshal_id       mid;
501   wine_marshal_data     md;
502   ULONG                 res;
503   LPMARSHAL             pMarshal;
504   LPUNKNOWN             pUnk;
505   CLSID                 xclsid;
506
507   TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(riid),ppv);
508
509   hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
510   if (hres) {
511       FIXME("Stream read 1 failed, %lx, (%ld of %d)\n",hres,res,sizeof(mid));
512       return hres;
513   }
514   hres = IStream_Read(pStm,&md,sizeof(md),&res);
515   if (hres) {
516       FIXME("Stream read 2 failed, %lx, (%ld of %d)\n",hres,res,sizeof(md));
517       return hres;
518   }
519   hres = IStream_Read(pStm,&xclsid,sizeof(xclsid),&res);
520   if (hres) {
521       FIXME("Stream read 3 failed, %lx, (%ld of %d)\n",hres,res,sizeof(xclsid));
522       return hres;
523   }
524   hres=CoCreateInstance(&xclsid,NULL,CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,&IID_IMarshal,(void**)&pUnk);
525   if (hres) {
526       FIXME("Failed to create instance of unmarshaller %s.\n",debugstr_guid(&xclsid));
527       return hres;
528   }
529   hres = _GetMarshaller(riid,pUnk,md.dwDestContext,NULL,md.mshlflags,&pMarshal);
530   if (hres) {
531       FIXME("Failed to get unmarshaller, %lx?\n",hres);
532       return hres;
533   }
534   hres = IMarshal_UnmarshalInterface(pMarshal,pStm,riid,ppv);
535   if (hres) {
536     FIXME("Failed to Unmarshal the interface, %lx?\n",hres);
537     goto release_marshal;
538   }
539 release_marshal:
540   IMarshal_Release(pMarshal);
541   return hres;
542 }
543
544 /***********************************************************************
545  *              CoMarshalInterThreadInterfaceInStream   [OLE32.33]
546  *
547  * Marshal interfaces across threads. We don't have a thread distinction,
548  * meaning most interfaces just work across different threads, the RPC
549  * handles it.
550  */
551 HRESULT WINAPI
552 CoMarshalInterThreadInterfaceInStream(
553   REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm
554 ) {
555   ULONG res;
556   ULARGE_INTEGER        xpos;
557   LARGE_INTEGER         seekto;
558   HRESULT               hres;
559
560   TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm);
561   hres = CreateStreamOnHGlobal(0, TRUE, ppStm);
562   if (hres) return hres;
563   /* CoMarshalInterface(...); */
564   hres = IStream_Write(*ppStm,&pUnk,sizeof(LPUNKNOWN),&res);
565   if (hres) return hres;
566   memset(&seekto,0,sizeof(seekto));
567   IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos);
568   return S_OK;
569 }
570
571 /***********************************************************************
572  *              CoGetInterfaceAndReleaseStream  [OLE32.19]
573  */
574 HRESULT WINAPI
575 CoGetInterfaceAndReleaseStream(LPSTREAM pStm,REFIID riid, LPVOID *ppv) {
576   ULONG res;
577   HRESULT               hres;
578   LPUNKNOWN             pUnk;
579
580   TRACE("(,%s,)\n",debugstr_guid(riid));
581   /* CoUnmarshalInterface(...); */
582   hres = IStream_Read(pStm,&pUnk,sizeof(LPUNKNOWN),&res);
583   if (hres) return hres;
584   IStream_Release(pStm);
585   return IUnknown_QueryInterface(pUnk,riid,ppv);
586 }
587
588 static HRESULT WINAPI
589 SMCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
590   *ppv = NULL;
591   if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IClassFactory)) {
592     *ppv = (LPVOID)iface;
593     return S_OK;
594   }
595   return E_NOINTERFACE;
596 }
597 static ULONG WINAPI SMCF_AddRef(LPCLASSFACTORY iface) { return 2; }
598 static ULONG WINAPI SMCF_Release(LPCLASSFACTORY iface) { return 1; }
599
600 static HRESULT WINAPI
601 SMCF_CreateInstance(
602   LPCLASSFACTORY iface, LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv
603 ) {
604   if (IsEqualIID(riid,&IID_IMarshal)) {
605       StdMarshalImpl    *dm;
606       dm=(StdMarshalImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
607       if (!dm)
608           return E_FAIL;
609       dm->lpvtbl        = &stdmvtbl;
610       dm->ref           = 1;
611       *ppv = (LPVOID)dm;
612       return S_OK;
613   }
614   FIXME("(%s), not supported.\n",debugstr_guid(riid));
615   return E_NOINTERFACE;
616 }
617
618 static HRESULT WINAPI
619 SMCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) {
620     FIXME("(%d), stub!\n",fLock);
621     return S_OK;
622 }
623
624 static ICOM_VTABLE(IClassFactory) dfmarshalcfvtbl = {
625     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
626     SMCF_QueryInterface,
627     SMCF_AddRef,
628     SMCF_Release,
629     SMCF_CreateInstance,
630     SMCF_LockServer
631 };
632 static ICOM_VTABLE(IClassFactory) *pdfmarshalcfvtbl = &dfmarshalcfvtbl;
633
634 HRESULT
635 MARSHAL_GetStandardMarshalCF(LPVOID *ppv) {
636   *ppv = &pdfmarshalcfvtbl;
637   return S_OK;
638 }