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