Jeroen Janssen wrote:
Hello,
After last weeks discussion on the "unhandled interface" message in CFProxy_QueryInterface I was getting, we concluded (if I'm correct) that this is part of the "IRemUnknown" handling that is not (yet) implemented correctly in the wine CVS tree.
I can't work out how IUnknown marshalling is getting delegated to the IClassFactory marshaller, but IUnknown marshalling should be a special case in StdMarshalImpl_UnmarshalInterface.
I'm trying to figure out exactly where in the (OLE) code, this should be handled. If someone could point me in the right direction I would appreciate it very much.
Does this patch help?
I think it would also be helpfull if there was some "fixme" logging so other people can also see if they hit upon the same problem (since it took a while to finally figure out the problem).
I suppose I could put a fixme in the above mentioned function that will alert you to this specific problem, but there are so many problems with the current code that putting in fixme's for all of them would take ages and I'd much rather prefer to be fixing them. If you'd like a list things not implemented in our current COM implementation then please let me know and I'll send one to you.
Rob
Index: wine/dlls/ole32/oleproxy.c =================================================================== RCS file: /home/wine/wine/dlls/ole32/oleproxy.c,v retrieving revision 1.17 diff -u -r1.17 oleproxy.c --- wine/dlls/ole32/oleproxy.c 22 Jul 2004 23:44:54 -0000 1.17 +++ wine/dlls/ole32/oleproxy.c 26 Jul 2004 10:53:20 -0000 @@ -139,7 +139,73 @@ ICOM_THIS(CFStub,iface); HRESULT hres;
- if (msg->iMethod == 3) { /* CreateInstance */ + if (msg->iMethod == 0) { /* QueryInterface */ + IID iid; + IClassFactory *classfac; + IUnknown *ppv; + IStream *pStm; + STATSTG ststg; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + ULONG res; + + if (msg->cbBuffer < sizeof(IID)) { + FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID)); + return E_FAIL; + } + memcpy(&iid,msg->Buffer,sizeof(iid)); + TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid)); + hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac); + if (hres) { + FIXME("Ole server does not provide a IClassFactory?\n"); + return hres; + } + hres = IClassFactory_QueryInterface(classfac,&iid,(LPVOID*)&ppv); + IClassFactory_Release(classfac); + if (hres) { + msg->cbBuffer = 0; + FIXME("Failed to QueryInterface %s\n",debugstr_guid(&iid)); + return hres; + } + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + FIXME("Failed to create stream on hglobal\n"); + return hres; + } + hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0); + if (hres) { + FIXME("CoMarshalInterface failed, %lx!\n",hres); + msg->cbBuffer = 0; + return hres; + } + hres = IStream_Stat(pStm,&ststg,0); + if (hres) { + FIXME("Stat failed.\n"); + return hres; + } + + msg->cbBuffer = ststg.cbSize.u.LowPart; + + if (msg->Buffer) + msg->Buffer = HeapReAlloc(GetProcessHeap(),0,msg->Buffer,ststg.cbSize.u.LowPart); + else + msg->Buffer = HeapAlloc(GetProcessHeap(),0,ststg.cbSize.u.LowPart); + + seekto.u.LowPart = 0;seekto.u.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + FIXME("IStream_Seek failed, %lx\n",hres); + return hres; + } + hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res); + if (hres) { + FIXME("Stream Read failed, %lx\n",hres); + return hres; + } + IStream_Release(pStm); + return S_OK; + } + else if (msg->iMethod == 3) { /* CreateInstance */ IID iid; IClassFactory *classfac; IUnknown *ppv; @@ -315,6 +381,12 @@
static HRESULT WINAPI CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + HRESULT hres; + LPSTREAM pStream; + HGLOBAL hGlobal; + ULONG srstatus; + RPCOLEMESSAGE msg; *ppv = NULL; if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) { *ppv = (LPVOID)iface; @@ -323,8 +395,49 @@ } if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */ return E_NOINTERFACE; - FIXME("Unhandled interface: %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; + + /* Send QueryInterface to the remote classfactory. + * + * Data: Only the 'IID'. + */ + msg.iMethod = 0; + msg.cbBuffer = sizeof(*riid); + msg.Buffer = NULL; + hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory); + if (hres) { + FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres); + return hres; + } + memcpy(msg.Buffer,riid,sizeof(*riid)); + hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus); + if (hres) { + FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres); + return hres; + } + + if (!msg.cbBuffer) /* interface not found on remote */ + return srstatus; + + /* We got back: [Marshalled Interface data] */ + TRACE("got %ld bytes data.\n",msg.cbBuffer); + hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer); + memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer); + hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream); + if (hres) { + FIXME("CreateStreamOnHGlobal failed with %lx\n",hres); + return hres; + } + hres = CoUnmarshalInterface( + pStream, + riid, + ppv + ); + IStream_Release(pStream); /* Does GlobalFree hGlobal too. */ + if (hres) { + FIXME("CoMarshalInterface failed, %lx\n",hres); + return hres; + } + return S_OK; }
static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {