handling IUnknown/IRemUnknown for (outproc) objects

Robert Shearman rob at codeweavers.com
Mon Jul 26 06:03:52 CDT 2004


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
-------------- next part --------------
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) {


More information about the wine-devel mailing list