Fix ref-counting rules to match native DCOM Dlls.
This commit is contained in:
parent
80083b18f8
commit
b3a4b59668
|
@ -628,6 +628,7 @@ static HRESULT proxy_manager_create_ifproxy(
|
||||||
if (IsEqualIID(riid, &IID_IUnknown))
|
if (IsEqualIID(riid, &IID_IUnknown))
|
||||||
{
|
{
|
||||||
ifproxy->iface = (void *)&This->lpVtbl;
|
ifproxy->iface = (void *)&This->lpVtbl;
|
||||||
|
IMultiQI_AddRef((IMultiQI *)&This->lpVtbl);
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -702,18 +703,19 @@ static void proxy_manager_disconnect(struct proxy_manager * This)
|
||||||
TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
|
TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid),
|
||||||
wine_dbgstr_longlong(This->oid));
|
wine_dbgstr_longlong(This->oid));
|
||||||
|
|
||||||
|
EnterCriticalSection(&This->cs);
|
||||||
|
|
||||||
/* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
|
/* SORFP_NOLIFTIMEMGMT proxies (for IRemUnknown) shouldn't be
|
||||||
* disconnected - it won't do anything anyway, except cause
|
* disconnected - it won't do anything anyway, except cause
|
||||||
* problems for other objects that depend on this proxy always
|
* problems for other objects that depend on this proxy always
|
||||||
* working */
|
* working */
|
||||||
if (This->sorflags & SORFP_NOLIFETIMEMGMT) return;
|
if (!(This->sorflags & SORFP_NOLIFETIMEMGMT))
|
||||||
|
|
||||||
EnterCriticalSection(&This->cs);
|
|
||||||
|
|
||||||
LIST_FOR_EACH(cursor, &This->interfaces)
|
|
||||||
{
|
{
|
||||||
struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
|
LIST_FOR_EACH(cursor, &This->interfaces)
|
||||||
ifproxy_disconnect(ifproxy);
|
{
|
||||||
|
struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry);
|
||||||
|
ifproxy_disconnect(ifproxy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* apartment is being destroyed so don't keep a pointer around to it */
|
/* apartment is being destroyed so don't keep a pointer around to it */
|
||||||
|
@ -986,12 +988,11 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI
|
||||||
hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
|
hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref,
|
||||||
riid, chanbuf, &ifproxy);
|
riid, chanbuf, &ifproxy);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
IUnknown_AddRef((IUnknown *)ifproxy->iface);
|
||||||
|
|
||||||
if (hr == S_OK)
|
if (hr == S_OK)
|
||||||
{
|
|
||||||
ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl);
|
|
||||||
*object = ifproxy->iface;
|
*object = ifproxy->iface;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release our reference to the proxy manager - the client/apartment
|
/* release our reference to the proxy manager - the client/apartment
|
||||||
|
|
|
@ -301,9 +301,8 @@ static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
|
||||||
ULONG ref = InterlockedDecrement(&This->ref);
|
ULONG ref = InterlockedDecrement(&This->ref);
|
||||||
|
|
||||||
if (!ref) {
|
if (!ref) {
|
||||||
IRpcChannelBuffer_Release(This->chanbuf);
|
IRpcProxyBuffer_Disconnect(iface);
|
||||||
This->chanbuf = NULL;
|
HeapFree(GetProcessHeap(),0,This);
|
||||||
HeapFree(GetProcessHeap(),0,This);
|
|
||||||
}
|
}
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
@ -451,11 +450,13 @@ CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
|
||||||
|
|
||||||
cf->lpvtbl_cf = &cfproxyvt;
|
cf->lpvtbl_cf = &cfproxyvt;
|
||||||
cf->lpvtbl_proxy = &pspbvtbl;
|
cf->lpvtbl_proxy = &pspbvtbl;
|
||||||
/* only one reference for the proxy buffer */
|
/* one reference for the proxy buffer */
|
||||||
cf->ref = 1;
|
cf->ref = 1;
|
||||||
cf->outer_unknown = pUnkOuter;
|
cf->outer_unknown = pUnkOuter;
|
||||||
*ppv = &(cf->lpvtbl_cf);
|
*ppv = &(cf->lpvtbl_cf);
|
||||||
*ppProxy = &(cf->lpvtbl_proxy);
|
*ppProxy = &(cf->lpvtbl_proxy);
|
||||||
|
/* and one reference for the object */
|
||||||
|
IUnknown_AddRef((IUnknown *)*ppv);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,9 +698,15 @@ static HRESULT WINAPI RemUnkProxy_QueryInterface(LPREMUNKNOWN iface, REFIID riid
|
||||||
static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface)
|
static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface)
|
||||||
{
|
{
|
||||||
RemUnkProxy *This = (RemUnkProxy *)iface;
|
RemUnkProxy *This = (RemUnkProxy *)iface;
|
||||||
|
ULONG refs;
|
||||||
|
|
||||||
TRACE("(%p)->AddRef()\n",This);
|
TRACE("(%p)->AddRef()\n",This);
|
||||||
return InterlockedIncrement(&This->refs);
|
|
||||||
|
if (This->outer_unknown)
|
||||||
|
refs = IUnknown_AddRef(This->outer_unknown);
|
||||||
|
else
|
||||||
|
refs = InterlockedIncrement(&This->refs);
|
||||||
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface)
|
static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface)
|
||||||
|
@ -870,8 +877,8 @@ static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
|
||||||
ULONG ref = InterlockedDecrement(&This->refs);
|
ULONG ref = InterlockedDecrement(&This->refs);
|
||||||
TRACE("%p, %ld\n", iface, ref);
|
TRACE("%p, %ld\n", iface, ref);
|
||||||
if (!ref) {
|
if (!ref) {
|
||||||
IRpcChannelBuffer_Release(This->chan);This->chan = NULL;
|
IRpcProxyBuffer_Disconnect(iface);
|
||||||
HeapFree(GetProcessHeap(),0,This);
|
HeapFree(GetProcessHeap(),0,This);
|
||||||
}
|
}
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
@ -917,6 +924,8 @@ RemUnkProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
|
||||||
This->outer_unknown = pUnkOuter;
|
This->outer_unknown = pUnkOuter;
|
||||||
*ppv = &(This->lpvtbl_remunk);
|
*ppv = &(This->lpvtbl_remunk);
|
||||||
*ppProxy = &(This->lpvtbl_proxy);
|
*ppProxy = &(This->lpvtbl_proxy);
|
||||||
|
/* and one reference for the object */
|
||||||
|
IUnknown_AddRef((IUnknown *)*ppv);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1282,6 +1282,82 @@ static void test_proxy_interfaces(void)
|
||||||
end_host_object(tid, thread);
|
end_host_object(tid, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const IUnknownVtbl *lpVtbl;
|
||||||
|
ULONG refs;
|
||||||
|
} HeapUnknown;
|
||||||
|
|
||||||
|
static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
if (IsEqualIID(riid, &IID_IUnknown))
|
||||||
|
{
|
||||||
|
IUnknown_AddRef(iface);
|
||||||
|
*ppv = (LPVOID)iface;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
*ppv = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
|
||||||
|
{
|
||||||
|
HeapUnknown *This = (HeapUnknown *)iface;
|
||||||
|
trace("HeapUnknown_AddRef(%p)\n", iface);
|
||||||
|
return InterlockedIncrement((LONG*)&This->refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
|
||||||
|
{
|
||||||
|
HeapUnknown *This = (HeapUnknown *)iface;
|
||||||
|
ULONG refs = InterlockedDecrement((LONG*)&This->refs);
|
||||||
|
trace("HeapUnknown_Release(%p)\n", iface);
|
||||||
|
if (!refs) HeapFree(GetProcessHeap(), 0, This);
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const IUnknownVtbl HeapUnknown_Vtbl =
|
||||||
|
{
|
||||||
|
HeapUnknown_QueryInterface,
|
||||||
|
HeapUnknown_AddRef,
|
||||||
|
HeapUnknown_Release
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_proxybuffer(REFIID riid)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IPSFactoryBuffer *psfb;
|
||||||
|
IRpcProxyBuffer *proxy;
|
||||||
|
LPVOID lpvtbl;
|
||||||
|
ULONG refs;
|
||||||
|
CLSID clsid;
|
||||||
|
HeapUnknown *pUnkOuter = (HeapUnknown *)HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
|
||||||
|
|
||||||
|
pUnkOuter->lpVtbl = &HeapUnknown_Vtbl;
|
||||||
|
pUnkOuter->refs = 1;
|
||||||
|
|
||||||
|
hr = CoGetPSClsid(riid, &clsid);
|
||||||
|
ok_ole_success(hr, CoGetPSClsid);
|
||||||
|
|
||||||
|
hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
|
||||||
|
ok_ole_success(hr, CoGetClassObject);
|
||||||
|
|
||||||
|
hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)pUnkOuter, riid, &proxy, &lpvtbl);
|
||||||
|
ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
|
||||||
|
ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
|
||||||
|
|
||||||
|
refs = IPSFactoryBuffer_Release(psfb);
|
||||||
|
#if 0 /* not reliable on native. maybe it leaks references! */
|
||||||
|
ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
refs = IUnknown_Release((IUnknown *)lpvtbl);
|
||||||
|
ok(refs == 1, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs-1);
|
||||||
|
|
||||||
|
refs = IRpcProxyBuffer_Release(proxy);
|
||||||
|
ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_stubbuffer(REFIID riid)
|
static void test_stubbuffer(REFIID riid)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -1428,96 +1504,6 @@ static void UnlockModuleOOP()
|
||||||
|
|
||||||
static HWND hwnd_app;
|
static HWND hwnd_app;
|
||||||
|
|
||||||
static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
|
|
||||||
LPCLASSFACTORY iface,
|
|
||||||
LPUNKNOWN pUnkOuter,
|
|
||||||
REFIID riid,
|
|
||||||
LPVOID *ppvObj)
|
|
||||||
{
|
|
||||||
DWORD res;
|
|
||||||
BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 500, &res);
|
|
||||||
todo_wine { ok(ret, "Timed out sending a message to originating window during RPC call\n"); }
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const IClassFactoryVtbl TestREClassFactory_Vtbl =
|
|
||||||
{
|
|
||||||
Test_IClassFactory_QueryInterface,
|
|
||||||
Test_IClassFactory_AddRef,
|
|
||||||
Test_IClassFactory_Release,
|
|
||||||
TestRE_IClassFactory_CreateInstance,
|
|
||||||
Test_IClassFactory_LockServer
|
|
||||||
};
|
|
||||||
|
|
||||||
IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
|
|
||||||
|
|
||||||
static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
||||||
{
|
|
||||||
switch (msg)
|
|
||||||
{
|
|
||||||
case WM_USER:
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
IStream *pStream = NULL;
|
|
||||||
IClassFactory *proxy = NULL;
|
|
||||||
IUnknown *object;
|
|
||||||
DWORD tid;
|
|
||||||
HANDLE thread;
|
|
||||||
|
|
||||||
cLocks = 0;
|
|
||||||
|
|
||||||
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
|
||||||
ok_ole_success(hr, CreateStreamOnHGlobal);
|
|
||||||
tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
|
|
||||||
|
|
||||||
ok_more_than_one_lock();
|
|
||||||
|
|
||||||
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
|
||||||
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
|
|
||||||
ok_ole_success(hr, CoReleaseMarshalData);
|
|
||||||
IStream_Release(pStream);
|
|
||||||
|
|
||||||
ok_more_than_one_lock();
|
|
||||||
|
|
||||||
hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
|
|
||||||
|
|
||||||
IClassFactory_Release(proxy);
|
|
||||||
|
|
||||||
ok_no_locks();
|
|
||||||
|
|
||||||
end_host_object(tid, thread);
|
|
||||||
|
|
||||||
PostMessage(hwnd, WM_QUIT, 0, 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_message_reentrancy()
|
|
||||||
{
|
|
||||||
WNDCLASS wndclass;
|
|
||||||
MSG msg;
|
|
||||||
|
|
||||||
memset(&wndclass, 0, sizeof(wndclass));
|
|
||||||
wndclass.lpfnWndProc = window_proc;
|
|
||||||
wndclass.lpszClassName = "WineCOMTest";
|
|
||||||
RegisterClass(&wndclass);
|
|
||||||
|
|
||||||
hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
|
|
||||||
ok(hwnd_app != NULL, "Window creation failed\n");
|
|
||||||
|
|
||||||
PostMessage(hwnd_app, WM_USER, 0, 0);
|
|
||||||
|
|
||||||
while (GetMessage(&msg, NULL, 0, 0))
|
|
||||||
{
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
|
static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
|
||||||
LPCLASSFACTORY iface,
|
LPCLASSFACTORY iface,
|
||||||
REFIID riid,
|
REFIID riid,
|
||||||
|
@ -1717,6 +1703,7 @@ START_TEST(marshal)
|
||||||
test_bad_marshal_stream();
|
test_bad_marshal_stream();
|
||||||
test_proxy_interfaces();
|
test_proxy_interfaces();
|
||||||
test_stubbuffer(&IID_IClassFactory);
|
test_stubbuffer(&IID_IClassFactory);
|
||||||
|
test_proxybuffer(&IID_IClassFactory);
|
||||||
test_message_reentrancy();
|
test_message_reentrancy();
|
||||||
|
|
||||||
/* test_out_of_process_com(); */
|
/* test_out_of_process_com(); */
|
||||||
|
|
|
@ -1967,13 +1967,14 @@ PSFacBuf_CreateProxy(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
proxy->lpvtbl2 = &tmproxyvtable;
|
proxy->lpvtbl2 = &tmproxyvtable;
|
||||||
/* 1 reference for the proxy and 1 for the object */
|
/* one reference for the proxy */
|
||||||
proxy->ref = 2;
|
proxy->ref = 1;
|
||||||
proxy->tinfo = tinfo;
|
proxy->tinfo = tinfo;
|
||||||
memcpy(&proxy->iid,riid,sizeof(*riid));
|
memcpy(&proxy->iid,riid,sizeof(*riid));
|
||||||
proxy->chanbuf = 0;
|
proxy->chanbuf = 0;
|
||||||
*ppv = (LPVOID)proxy;
|
*ppv = (LPVOID)proxy;
|
||||||
*ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
|
*ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
|
||||||
|
IUnknown_AddRef((IUnknown *)*ppv);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,8 +176,8 @@ HRESULT WINAPI StdProxy_Construct(REFIID riid,
|
||||||
This->PVtbl = vtbl->Vtbl;
|
This->PVtbl = vtbl->Vtbl;
|
||||||
|
|
||||||
This->lpVtbl = &StdProxy_Vtbl;
|
This->lpVtbl = &StdProxy_Vtbl;
|
||||||
/* 1 reference for the proxy and 1 for the object */
|
/* one reference for the proxy */
|
||||||
This->RefCount = 2;
|
This->RefCount = 1;
|
||||||
This->stubless = stubless;
|
This->stubless = stubless;
|
||||||
This->piid = vtbl->header.piid;
|
This->piid = vtbl->header.piid;
|
||||||
This->pUnkOuter = pUnkOuter;
|
This->pUnkOuter = pUnkOuter;
|
||||||
|
@ -186,6 +186,7 @@ HRESULT WINAPI StdProxy_Construct(REFIID riid,
|
||||||
This->pChannel = NULL;
|
This->pChannel = NULL;
|
||||||
*ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl;
|
*ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl;
|
||||||
*ppvObj = &This->PVtbl;
|
*ppvObj = &This->PVtbl;
|
||||||
|
IUnknown_AddRef((IUnknown *)*ppvObj);
|
||||||
IPSFactoryBuffer_AddRef(pPSFactory);
|
IPSFactoryBuffer_AddRef(pPSFactory);
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
Loading…
Reference in New Issue