- 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.
This commit is contained in:
parent
08255295e4
commit
6a20b2f476
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hres;
|
||||
if (proxy_manager) ClientIdentity_Release((IInternalUnknown*)&proxy_manager->lpVtbl);
|
||||
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue