Commit 6a20b2f4 authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

- Initialize ppv pointer in ClientIdentity_QueryInterface to NULL as

apps depend on this. - Don't release IRpcProxyBuffer on ifproxy destruction - the caller will do this for us. - Make find_proxy_manager add a reference to the proxy manager and make proxy_manager_construct return an object with a valid ref-count. - Remove stray not operator to fix a memory leak / crash in proxy_manager_destroy. - More debug messages, especially on errors. - Fix ref-count leak in the Class Factory proxy. - Add a test case for IClassFactory_CreateInstance.
parent 08255295
......@@ -195,6 +195,8 @@ static HRESULT WINAPI ClientIdentity_QueryInterface(IInternalUnknown * iface, RE
FIXME("interface not found %s\n", debugstr_guid(riid));
/* FIXME: call IRemUnknown::RemQueryInterface */
*ppv = NULL;
return E_NOINTERFACE;
}
......@@ -283,13 +285,18 @@ static void ifproxy_disconnect(struct ifproxy * This)
static void ifproxy_destroy(struct ifproxy * This)
{
TRACE("%p\n", This);
/* release public references to this object so that the stub can know
* when to destroy itself */
ifproxy_release_public_refs(This);
list_remove(&This->entry);
if (This->proxy) IRpcProxyBuffer_Release(This->proxy);
/* note: we don't call Release for This->proxy because its lifetime is
* controlled by the return value from ClientIdentity_Release, which this
* function is always called from */
HeapFree(GetProcessHeap(), 0, This);
}
......@@ -312,7 +319,7 @@ static HRESULT proxy_manager_construct(APARTMENT * apt, OXID oxid, OID oid, IRpc
This->oxid = oxid;
This->oid = oid;
This->refs = 0; /* will be incremented on creation of first proxy */
This->refs = 1;
This->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
......@@ -349,7 +356,13 @@ static HRESULT proxy_manager_create_ifproxy(struct proxy_manager * This, IPID ip
hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid,
&ifproxy->proxy, &ifproxy->iface);
IPSFactoryBuffer_Release(psfb);
if (hr != S_OK)
ERR("Could not create proxy for interface %s, error 0x%08lx\n",
debugstr_guid(riid), hr);
}
else
ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08lx\n",
debugstr_guid(riid), hr);
if (hr == S_OK)
hr = IRpcProxyBuffer_Connect(ifproxy->proxy, This->chan);
......@@ -365,6 +378,8 @@ static HRESULT proxy_manager_create_ifproxy(struct proxy_manager * This, IPID ip
LeaveCriticalSection(&This->cs);
*iif_out = ifproxy;
TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n",
ifproxy, debugstr_guid(&ipid), debugstr_guid(riid), cPublicRefs);
}
else
ifproxy_destroy(ifproxy);
......@@ -440,7 +455,7 @@ static void proxy_manager_destroy(struct proxy_manager * This)
}
/* destroy all of the interface proxies */
while (!(cursor = list_head(&This->interfaces)))
while ((cursor = list_head(&This->interfaces)))
{
struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
ifproxy_destroy(ifproxy);
......@@ -453,6 +468,9 @@ static void proxy_manager_destroy(struct proxy_manager * This)
HeapFree(GetProcessHeap(), 0, This);
}
/* finds the proxy manager corresponding to a given OXID and OID that has
* been unmarshaled in the specified apartment. The caller must release the
* reference to the proxy_manager when the object is no longer used. */
static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found)
{
BOOL found = FALSE;
......@@ -465,6 +483,7 @@ static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy
if ((oxid == proxy->oxid) && (oid == proxy->oid))
{
*proxy_found = proxy;
ClientIdentity_AddRef((IInternalUnknown *)&proxy->lpVtbl);
found = TRUE;
break;
}
......@@ -616,8 +635,7 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v
wine_marshal_id mid;
ULONG res;
HRESULT hres;
IRpcChannelBuffer *chanbuf;
struct proxy_manager *proxy_manager;
struct proxy_manager *proxy_manager = NULL;
APARTMENT *apt = COM_CurrentApt();
APARTMENT *stub_apt;
ULONG cPublicRefs = 1;
......@@ -683,25 +701,45 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v
if (!find_proxy_manager(apt, mid.oxid, mid.oid, &proxy_manager))
{
IRpcChannelBuffer *chanbuf;
hres = PIPE_GetNewPipeBuf(&mid,&chanbuf);
if (hres == S_OK)
hres = proxy_manager_construct(apt, mid.oxid, mid.oid, chanbuf, &proxy_manager);
}
if (hres == S_OK)
{
struct ifproxy * ifproxy;
hres = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
if (hres == S_OK)
IUnknown_AddRef((IUnknown *)ifproxy->iface);
else if (hres == E_NOINTERFACE)
hres = proxy_manager_create_ifproxy(proxy_manager, mid.ipid, riid, cPublicRefs, &ifproxy);
{
/* the IUnknown interface is special because it does not have an
* ifproxy associated with it. we simply return the controlling
* IUnknown of the proxy manager. */
if (IsEqualIID(riid, &IID_IUnknown))
{
ClientIdentity_AddRef((IInternalUnknown*)&proxy_manager->lpVtbl);
*ppv = (LPVOID)(&proxy_manager->lpVtbl);
}
else
{
struct ifproxy * ifproxy;
hres = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy);
if (hres == E_NOINTERFACE)
hres = proxy_manager_create_ifproxy(proxy_manager, mid.ipid,
riid, cPublicRefs, &ifproxy);
if (hres == S_OK)
*ppv = ifproxy->iface; /* AddRef'd above */
}
if (hres == S_OK)
{
/* FIXME: push this AddRef inside proxy_manager_find_ifproxy/create_ifproxy? */
ClientIdentity_AddRef((IInternalUnknown*)&proxy_manager->lpVtbl);
*ppv = ifproxy->iface;
}
}
}
if (proxy_manager) ClientIdentity_Release((IInternalUnknown*)&proxy_manager->lpVtbl);
return hres;
if (hres) WARN("Failed with error 0x%08lx\n", hres);
else TRACE("Successfully created proxy %p\n", *ppv);
return hres;
}
static HRESULT WINAPI
......
......@@ -175,6 +175,7 @@ CFStub_Invoke(
return hres;
}
hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
IUnknown_Release((IUnknown*)ppv);
if (hres) {
FIXME("CoMarshalInterface failed, %lx!\n",hres);
msg->cbBuffer = 0;
......@@ -443,13 +444,11 @@ CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
cf->lpvtbl_cf = &cfproxyvt;
cf->lpvtbl_proxy = &pspbvtbl;
/* 1 reference for the proxy... */
/* only one reference for the proxy buffer */
cf->ref = 1;
cf->outer_unknown = pUnkOuter;
*ppv = &(cf->lpvtbl_cf);
*ppProxy = &(cf->lpvtbl_proxy);
/* ...and 1 for the object */
IUnknown_AddRef((IUnknown *)*ppv);
return S_OK;
}
......
......@@ -51,6 +51,45 @@ static void UnlockModule()
}
static HRESULT WINAPI Test_IUnknown_QueryInterface(
LPUNKNOWN iface,
REFIID riid,
LPVOID *ppvObj)
{
if (ppvObj == NULL) return E_POINTER;
if (IsEqualGUID(riid, &IID_IUnknown))
{
*ppvObj = (LPVOID)iface;
IUnknown_AddRef(iface);
return S_OK;
}
return E_NOINTERFACE;
}
static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
{
LockModule();
return 2; /* non-heap-based object */
}
static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
{
UnlockModule();
return 1; /* non-heap-based object */
}
static IUnknownVtbl TestUnknown_Vtbl =
{
Test_IUnknown_QueryInterface,
Test_IUnknown_AddRef,
Test_IUnknown_Release,
};
static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
static HRESULT WINAPI Test_IClassFactory_QueryInterface(
LPCLASSFACTORY iface,
REFIID riid,
......@@ -87,7 +126,8 @@ static HRESULT WINAPI Test_IClassFactory_CreateInstance(
REFIID riid,
LPVOID *ppvObj)
{
return CLASS_E_CLASSNOTAVAILABLE;
if (pUnkOuter) return CLASS_E_NOAGGREGATION;
return IUnknown_QueryInterface((IUnknown*)&Test_Unknown, riid, ppvObj);
}
static HRESULT WINAPI Test_IClassFactory_LockServer(
......@@ -582,12 +622,12 @@ static DWORD CALLBACK bad_thread_proc(LPVOID p)
{
IClassFactory * cf = (IClassFactory *)p;
HRESULT hr;
IUnknown * dummy;
IUnknown * proxy = NULL;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&dummy);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
if (proxy) IUnknown_Release(proxy);
todo_wine {
ok(hr == RPC_E_WRONG_THREAD,
"COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n",
......@@ -726,7 +766,7 @@ static void test_message_filter()
IStream *pStream = NULL;
IClassFactory *cf = NULL;
DWORD tid;
IUnknown *dummy;
IUnknown *proxy = NULL;
IMessageFilter *prev_filter = NULL;
HANDLE thread;
......@@ -740,20 +780,24 @@ static void test_message_filter()
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
ok_ole_success(hr, CoReleaseMarshalData);
ok_ole_success(hr, CoUnmarshalInterface);
IStream_Release(pStream);
ok_more_than_one_lock();
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&dummy);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
todo_wine { ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08lx instead\n", hr); }
if (proxy) IUnknown_Release(proxy);
proxy = NULL;
hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
ok_ole_success(hr, CoRegisterMessageFilter);
if (prev_filter) IMessageFilter_Release(prev_filter);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&dummy);
ok(hr == CLASS_E_CLASSNOTAVAILABLE, "Call didn't wasn't accepted. hr = 0x%08lx\n", hr);
hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
ok_ole_success(hr, IClassFactory_CreateInstance);
IUnknown_Release(proxy);
IClassFactory_Release(cf);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment