4 * Copyright 2002 Marcus Meissner
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.
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.
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
39 #include "wine/unicode.h"
40 #include "wine/winbase16.h"
41 #include "compobj_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(ole);
48 extern const CLSID CLSID_DfMarshal;
50 /* Marshalling just passes a unique identifier to the remote client,
51 * that makes it possible to find the passed interface again.
53 * So basically we need a set of values that make it unique.
55 * Process Identifier, Object IUnknown ptr, IID
57 * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value!
60 typedef struct _mid2unknown {
65 typedef struct _mid2stub {
71 static mid2stub *stubs = NULL;
72 static int nrofstubs = 0;
74 static mid2unknown *proxies = NULL;
75 static int nrofproxies = 0;
78 MARSHAL_Find_Stub_Server(wine_marshal_id *mid,LPUNKNOWN *punk) {
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));
92 MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub) {
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));
106 MARSHAL_Find_Stub(wine_marshal_id *mid,LPUNKNOWN *pUnk) {
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));
120 MARSHAL_Register_Stub(wine_marshal_id *mid,LPUNKNOWN pUnk,IRpcStubBuffer *stub) {
122 if (!MARSHAL_Find_Stub(mid,&xPunk)) {
123 FIXME("Already have entry for (%lx/%s)!\n",mid->objectid,debugstr_guid(&(mid->iid)));
127 stubs=HeapReAlloc(GetProcessHeap(),0,stubs,sizeof(stubs[0])*(nrofstubs+1));
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));
139 MARSHAL_Find_Proxy(wine_marshal_id *mid,LPUNKNOWN *punk) {
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));
152 MARSHAL_Find_Proxy_Object(wine_marshal_id *mid,LPUNKNOWN *punk) {
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));
165 MARSHAL_Register_Proxy(wine_marshal_id *mid,LPUNKNOWN punk) {
168 for (i=0;i<nrofproxies;i++) {
169 if (MARSHAL_Compare_Mids(mid,&(proxies[i].mid))) {
170 ERR("Already have mid?\n");
175 proxies = HeapReAlloc(GetProcessHeap(),0,proxies,sizeof(proxies[0])*(nrofproxies+1));
177 proxies = HeapAlloc(GetProcessHeap(),0,sizeof(proxies[0]));
178 memcpy(&(proxies[nrofproxies].mid),mid,sizeof(*mid));
179 proxies[nrofproxies].pUnk = punk;
181 IUnknown_AddRef(punk);
185 /********************** StdMarshal implementation ****************************/
186 typedef struct _StdMarshalImpl {
187 ICOM_VTABLE(IMarshal) *lpvtbl;
192 LPVOID pvDestContext;
197 StdMarshalImpl_QueryInterface(LPMARSHAL iface,REFIID riid,LPVOID *ppv) {
199 if (IsEqualIID(&IID_IUnknown,riid) || IsEqualIID(&IID_IMarshal,riid)) {
201 IUnknown_AddRef(iface);
204 FIXME("No interface for %s.\n",debugstr_guid(riid));
205 return E_NOINTERFACE;
209 StdMarshalImpl_AddRef(LPMARSHAL iface) {
210 ICOM_THIS(StdMarshalImpl,iface);
216 StdMarshalImpl_Release(LPMARSHAL iface) {
217 ICOM_THIS(StdMarshalImpl,iface);
222 HeapFree(GetProcessHeap(),0,This);
227 StdMarshalImpl_GetUnmarshalClass(
228 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
229 void* pvDestContext, DWORD mshlflags, CLSID* pCid
231 memcpy(pCid,&CLSID_DfMarshal,sizeof(CLSID_DfMarshal));
236 StdMarshalImpl_GetMarshalSizeMax(
237 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
238 void* pvDestContext, DWORD mshlflags, DWORD* pSize
240 *pSize = sizeof(wine_marshal_id)+sizeof(wine_marshal_data);
245 StdMarshalImpl_MarshalInterface(
246 LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext,
247 void* pvDestContext, DWORD mshlflags
250 wine_marshal_data md;
254 IRpcStubBuffer *stub;
255 IPSFactoryBuffer *psfacbuf;
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;
270 if (SUCCEEDED(MARSHAL_Find_Stub(&mid,&pUnk))) {
271 IUnknown_Release(pUnk);
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);
279 FIXME("Failed to create a stub for %s\n",debugstr_guid(riid));
282 IUnknown_QueryInterface((LPUNKNOWN)pv,riid,(LPVOID*)&pUnk);
283 MARSHAL_Register_Stub(&mid,pUnk,stub);
284 IUnknown_Release(pUnk);
289 StdMarshalImpl_UnmarshalInterface(
290 LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv
293 wine_marshal_data md;
296 IPSFactoryBuffer *psfacbuf;
297 IRpcProxyBuffer *rpcproxy;
298 IRpcChannelBuffer *chanbuf;
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));
309 hres = get_facbuf_for_iid(riid,&psfacbuf);
310 if (hres) return hres;
311 hres = IPSFactoryBuffer_CreateProxy(psfacbuf,NULL,riid,&rpcproxy,ppv);
313 FIXME("Failed to create a proxy for %s\n",debugstr_guid(riid));
316 hres = PIPE_GetNewPipeBuf(&mid,&chanbuf);
318 ERR("Failed to get an rpc channel buffer for %s\n",debugstr_guid(riid));
320 IRpcProxyBuffer_Connect(rpcproxy,chanbuf);
321 IRpcProxyBuffer_Release(rpcproxy); /* no need */
323 IPSFactoryBuffer_Release(psfacbuf);
328 StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) {
329 FIXME("(), stub!\n");
334 StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) {
335 FIXME("(), stub!\n");
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
352 /***********************************************************************
353 * CoGetStandardMarshal [OLE32.23]
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
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.
366 CoGetStandardMarshal(
367 REFIID riid,IUnknown *pUnk,DWORD dwDestContext,LPVOID pvDestContext,
368 DWORD mshlflags, LPMARSHAL *pMarshal
373 FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n",
374 debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,pMarshal
378 TRACE("(%s,%p,%lx,%p,%lx,%p)\n",
379 debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,pMarshal
381 dm = (StdMarshalImpl*) *pMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
382 if (!dm) return E_FAIL;
383 dm->lpvtbl = &stdmvtbl;
386 memcpy(&dm->iid,riid,sizeof(dm->iid));
387 dm->dwDestContext = dwDestContext;
388 dm->pvDestContext = pvDestContext;
389 dm->mshlflags = mshlflags;
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
402 hres = IUnknown_QueryInterface(pUnk,&IID_IMarshal,(LPVOID*)pMarshal);
404 hres = CoGetStandardMarshal(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,pMarshal);
408 /***********************************************************************
409 * CoGetMarshalSizeMax [OLE32.21]
412 CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
413 DWORD dwDestContext, void *pvDestContext, DWORD mshlFlags
418 hres = _GetMarshaller(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,&pMarshal);
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);
428 /***********************************************************************
429 * CoMarshalInterface [OLE32.34]
432 CoMarshalInterface( IStream *pStm, REFIID riid, IUnknown *pUnk,
433 DWORD dwDestContext, void *pvDestContext, DWORD mshlflags
440 wine_marshal_data md;
444 TRACE("(%p, %s, %p, %lx, %p, %lx)\n",
445 pStm,debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags
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);
461 FIXME("Failed to get marshaller, %lx?\n",hres);
464 hres = IMarshal_GetUnmarshalClass(pMarshal,riid,pUnk,dwDestContext,pvDestContext,mshlflags,&xclsid);
466 FIXME("IMarshal:GetUnmarshalClass failed, %lx\n",hres);
467 goto release_marshal;
469 hres = IStream_Write(pStm,&xclsid,sizeof(xclsid),&writeres);
471 FIXME("Stream write failed, %lx\n",hres);
472 goto release_marshal;
474 hres = IMarshal_MarshalInterface(pMarshal,pStm,riid,pUnk,dwDestContext,pvDestContext,mshlflags);
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");
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");
483 FIXME("Failed to marshal the interface %s, %lx?\n",debugstr_guid(riid),hres);
486 goto release_marshal;
489 IMarshal_Release(pMarshal);
494 /***********************************************************************
495 * CoUnmarshalInterface [OLE32.50]
498 CoUnmarshalInterface(IStream *pStm, REFIID riid, LPVOID *ppv) {
501 wine_marshal_data md;
507 TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(riid),ppv);
509 hres = IStream_Read(pStm,&mid,sizeof(mid),&res);
511 FIXME("Stream read 1 failed, %lx, (%ld of %d)\n",hres,res,sizeof(mid));
514 hres = IStream_Read(pStm,&md,sizeof(md),&res);
516 FIXME("Stream read 2 failed, %lx, (%ld of %d)\n",hres,res,sizeof(md));
519 hres = IStream_Read(pStm,&xclsid,sizeof(xclsid),&res);
521 FIXME("Stream read 3 failed, %lx, (%ld of %d)\n",hres,res,sizeof(xclsid));
524 hres=CoCreateInstance(&xclsid,NULL,CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,&IID_IMarshal,(void**)&pUnk);
526 FIXME("Failed to create instance of unmarshaller %s.\n",debugstr_guid(&xclsid));
529 hres = _GetMarshaller(riid,pUnk,md.dwDestContext,NULL,md.mshlflags,&pMarshal);
531 FIXME("Failed to get unmarshaller, %lx?\n",hres);
534 hres = IMarshal_UnmarshalInterface(pMarshal,pStm,riid,ppv);
536 FIXME("Failed to Unmarshal the interface, %lx?\n",hres);
537 goto release_marshal;
540 IMarshal_Release(pMarshal);
544 /***********************************************************************
545 * CoMarshalInterThreadInterfaceInStream [OLE32.33]
547 * Marshal interfaces across threads. We don't have a thread distinction,
548 * meaning most interfaces just work across different threads, the RPC
552 CoMarshalInterThreadInterfaceInStream(
553 REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm
557 LARGE_INTEGER seekto;
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);
571 /***********************************************************************
572 * CoGetInterfaceAndReleaseStream [OLE32.19]
575 CoGetInterfaceAndReleaseStream(LPSTREAM pStm,REFIID riid, LPVOID *ppv) {
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);
588 static HRESULT WINAPI
589 SMCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
591 if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IClassFactory)) {
592 *ppv = (LPVOID)iface;
595 return E_NOINTERFACE;
597 static ULONG WINAPI SMCF_AddRef(LPCLASSFACTORY iface) { return 2; }
598 static ULONG WINAPI SMCF_Release(LPCLASSFACTORY iface) { return 1; }
600 static HRESULT WINAPI
602 LPCLASSFACTORY iface, LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv
604 if (IsEqualIID(riid,&IID_IMarshal)) {
606 dm=(StdMarshalImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl));
609 dm->lpvtbl = &stdmvtbl;
614 FIXME("(%s), not supported.\n",debugstr_guid(riid));
615 return E_NOINTERFACE;
618 static HRESULT WINAPI
619 SMCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) {
620 FIXME("(%d), stub!\n",fLock);
624 static ICOM_VTABLE(IClassFactory) dfmarshalcfvtbl = {
625 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
632 static ICOM_VTABLE(IClassFactory) *pdfmarshalcfvtbl = &dfmarshalcfvtbl;
635 MARSHAL_GetStandardMarshalCF(LPVOID *ppv) {
636 *ppv = &pdfmarshalcfvtbl;