- More tests.
- Change return code of CoGetPSClsid to match test result. - Do a slight hack to make IRemUnknown proxies be added after the proxy that uses them to stop them being used after they are destroyed. - Fix multiple local server connections.
This commit is contained in:
parent
2a0df4bd60
commit
9b634b97ae
|
@ -1060,8 +1060,8 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* CoGetPSClsid [OLE32.@]
|
* CoGetPSClsid [OLE32.@]
|
||||||
*
|
*
|
||||||
* This function returns the CLSID of the proxy/stub factory that
|
* Retrieves the CLSID of the proxy/stub factory that implements
|
||||||
* implements IPSFactoryBuffer for the specified interface.
|
* IPSFactoryBuffer for the specified interface.
|
||||||
*
|
*
|
||||||
* PARAMS
|
* PARAMS
|
||||||
* riid [I] Interface whose proxy/stub CLSID is to be returned.
|
* riid [I] Interface whose proxy/stub CLSID is to be returned.
|
||||||
|
@ -1070,7 +1070,7 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
|
||||||
* RETURNS
|
* RETURNS
|
||||||
* S_OK
|
* S_OK
|
||||||
* E_OUTOFMEMORY
|
* E_OUTOFMEMORY
|
||||||
* E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
|
* REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
|
@ -1088,6 +1088,9 @@ HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
|
||||||
*
|
*
|
||||||
* We only search the registry, not ids registered with
|
* We only search the registry, not ids registered with
|
||||||
* CoRegisterPSClsid.
|
* CoRegisterPSClsid.
|
||||||
|
* Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
|
||||||
|
* without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
|
||||||
|
* considered a bug in native unless an application depends on this (unlikely).
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
|
HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
|
||||||
{
|
{
|
||||||
|
@ -1103,9 +1106,7 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
|
||||||
(length of iid string plus constant length of static text */
|
(length of iid string plus constant length of static text */
|
||||||
buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
|
buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
{
|
return E_OUTOFMEMORY;
|
||||||
return (E_OUTOFMEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Construct the registry key we want */
|
/* Construct the registry key we want */
|
||||||
sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
|
sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
|
||||||
|
@ -1113,9 +1114,9 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
|
||||||
/* Open the key.. */
|
/* Open the key.. */
|
||||||
if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
|
if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
|
||||||
{
|
{
|
||||||
WARN("No PSFactoryBuffer object is registered for this IID\n");
|
WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
|
||||||
HeapFree(GetProcessHeap(),0,buf);
|
HeapFree(GetProcessHeap(),0,buf);
|
||||||
return (E_INVALIDARG);
|
return REGDB_E_IIDNOTREG;
|
||||||
}
|
}
|
||||||
HeapFree(GetProcessHeap(),0,buf);
|
HeapFree(GetProcessHeap(),0,buf);
|
||||||
|
|
||||||
|
@ -1125,19 +1126,18 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
|
||||||
buf2len = sizeof(buf2);
|
buf2len = sizeof(buf2);
|
||||||
if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
|
if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
|
||||||
{
|
{
|
||||||
RegCloseKey(xhkey);
|
RegCloseKey(xhkey);
|
||||||
return E_INVALIDARG;
|
return REGDB_E_IIDNOTREG;
|
||||||
}
|
}
|
||||||
RegCloseKey(xhkey);
|
RegCloseKey(xhkey);
|
||||||
|
|
||||||
/* We have the CLSid we want back from the registry as a string, so
|
/* We have the CLSid we want back from the registry as a string, so
|
||||||
lets convert it into a CLSID structure */
|
lets convert it into a CLSID structure */
|
||||||
if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
|
if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
|
||||||
return E_INVALIDARG;
|
return REGDB_E_IIDNOTREG;
|
||||||
}
|
|
||||||
|
|
||||||
TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
|
TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
|
||||||
return (S_OK);
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -423,13 +423,19 @@ static HRESULT proxy_manager_construct(
|
||||||
* should store the STDOBJREF flags in the proxy manager. */
|
* should store the STDOBJREF flags in the proxy manager. */
|
||||||
This->sorflags = sorflags;
|
This->sorflags = sorflags;
|
||||||
|
|
||||||
|
assert(channel);
|
||||||
This->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
|
This->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */
|
||||||
|
|
||||||
/* we create the IRemUnknown proxy on demand */
|
/* we create the IRemUnknown proxy on demand */
|
||||||
This->remunk = NULL;
|
This->remunk = NULL;
|
||||||
|
|
||||||
EnterCriticalSection(&apt->cs);
|
EnterCriticalSection(&apt->cs);
|
||||||
list_add_head(&apt->proxies, &This->entry);
|
/* FIXME: we are dependent on the ordering in here to make sure a proxy's
|
||||||
|
* IRemUnknown proxy doesn't get destroyed before the regual proxy does
|
||||||
|
* because we need the IRemUnknown proxy during the destruction of the
|
||||||
|
* regular proxy. Ideally, we should maintain a separate list for the
|
||||||
|
* IRemUnknown proxies that need late destruction */
|
||||||
|
list_add_tail(&apt->proxies, &This->entry);
|
||||||
LeaveCriticalSection(&apt->cs);
|
LeaveCriticalSection(&apt->cs);
|
||||||
|
|
||||||
TRACE("%p created for OXID %s, OID %s\n", This,
|
TRACE("%p created for OXID %s, OID %s\n", This,
|
||||||
|
@ -790,7 +796,13 @@ StdMarshalImpl_MarshalInterface(
|
||||||
start_apartment_listener_thread(); /* just to be sure we have one running. */
|
start_apartment_listener_thread(); /* just to be sure we have one running. */
|
||||||
start_apartment_remote_unknown();
|
start_apartment_remote_unknown();
|
||||||
|
|
||||||
IUnknown_QueryInterface((LPUNKNOWN)pv, riid, (LPVOID*)&pUnk);
|
hres = IUnknown_QueryInterface((LPUNKNOWN)pv, riid, (LPVOID*)&pUnk);
|
||||||
|
if (hres != S_OK)
|
||||||
|
{
|
||||||
|
ERR("object doesn't expose interface %s, failing with error 0x%08lx\n",
|
||||||
|
debugstr_guid(riid), hres);
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
if ((manager = get_stub_manager_from_object(apt, pUnk)))
|
if ((manager = get_stub_manager_from_object(apt, pUnk)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -991,8 +991,6 @@ static DWORD WINAPI local_server_thread(LPVOID param)
|
||||||
return hres;
|
return hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
IStream_Release(pStm);
|
|
||||||
|
|
||||||
WriteFile(hPipe,buffer,buflen,&res,NULL);
|
WriteFile(hPipe,buffer,buflen,&res,NULL);
|
||||||
FlushFileBuffers(hPipe);
|
FlushFileBuffers(hPipe);
|
||||||
DisconnectNamedPipe(hPipe);
|
DisconnectNamedPipe(hPipe);
|
||||||
|
@ -1000,6 +998,7 @@ static DWORD WINAPI local_server_thread(LPVOID param)
|
||||||
TRACE("done marshalling IClassFactory\n");
|
TRACE("done marshalling IClassFactory\n");
|
||||||
}
|
}
|
||||||
CloseHandle(hPipe);
|
CloseHandle(hPipe);
|
||||||
|
IStream_Release(pStm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,26 @@ HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
|
||||||
#define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %ld\n", cLocks)
|
#define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %ld\n", cLocks)
|
||||||
#define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", hr)
|
#define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", hr)
|
||||||
|
|
||||||
|
static void test_CoGetPSClsid()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
CLSID clsid;
|
||||||
|
static const CLSID IID_IWineTest = {
|
||||||
|
0x5201163f,
|
||||||
|
0x8164,
|
||||||
|
0x4fd0,
|
||||||
|
{0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
|
||||||
|
}; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
|
||||||
|
|
||||||
|
hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
|
||||||
|
ok_ole_success(hr, CoGetPSClsid);
|
||||||
|
|
||||||
|
hr = CoGetPSClsid(&IID_IWineTest, &clsid);
|
||||||
|
ok(hr == REGDB_E_IIDNOTREG,
|
||||||
|
"CoGetPSClsid for random IID returned 0x%08lx instead of REGDB_E_IIDNOTREG\n",
|
||||||
|
hr);
|
||||||
|
}
|
||||||
|
|
||||||
static const LARGE_INTEGER ullZero;
|
static const LARGE_INTEGER ullZero;
|
||||||
static LONG cLocks;
|
static LONG cLocks;
|
||||||
|
|
||||||
|
@ -251,6 +271,27 @@ static void end_host_object(DWORD tid, HANDLE thread)
|
||||||
CloseHandle(thread);
|
CloseHandle(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tests failure case of interface not having a marshaler specified in the
|
||||||
|
* registry */
|
||||||
|
static void test_no_marshaler()
|
||||||
|
{
|
||||||
|
IStream *pStream;
|
||||||
|
HRESULT hr;
|
||||||
|
static const CLSID IID_IWineTest = {
|
||||||
|
0x5201163f,
|
||||||
|
0x8164,
|
||||||
|
0x4fd0,
|
||||||
|
{0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
|
||||||
|
}; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||||
|
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||||
|
hr = CoMarshalInterface(pStream, &IID_IWineTest, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
|
||||||
|
ok(hr == E_NOINTERFACE, "CoMarshalInterface should have returned E_NOINTERFACE instead of 0x%08lx\n", hr);
|
||||||
|
|
||||||
|
IStream_Release(pStream);
|
||||||
|
}
|
||||||
|
|
||||||
/* tests normal marshal and then release without unmarshaling */
|
/* tests normal marshal and then release without unmarshaling */
|
||||||
static void test_normal_marshal_and_release()
|
static void test_normal_marshal_and_release()
|
||||||
{
|
{
|
||||||
|
@ -302,6 +343,49 @@ static void test_normal_marshal_and_unmarshal()
|
||||||
ok_no_locks();
|
ok_no_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tests failure case of a unmarshaling an freed object */
|
||||||
|
static void test_marshal_and_unmarshal_invalid()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IStream *pStream = NULL;
|
||||||
|
IClassFactory *pProxy = NULL;
|
||||||
|
DWORD tid;
|
||||||
|
void * dummy;
|
||||||
|
HANDLE thread;
|
||||||
|
|
||||||
|
cLocks = 0;
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||||
|
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||||
|
tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoReleaseMarshalData(pStream);
|
||||||
|
ok_ole_success(hr, CoReleaseMarshalData);
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
|
||||||
|
todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
|
||||||
|
if (pProxy)
|
||||||
|
{
|
||||||
|
hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, &dummy);
|
||||||
|
ok(hr == RPC_E_DISCONNECTED, "Remote call should have returned RPC_E_DISCONNECTED, instead of 0x%08lx\n", hr);
|
||||||
|
|
||||||
|
IClassFactory_Release(pProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
IStream_Release(pStream);
|
||||||
|
|
||||||
|
end_host_object(tid, thread);
|
||||||
|
}
|
||||||
|
|
||||||
/* tests success case of an interthread marshal */
|
/* tests success case of an interthread marshal */
|
||||||
static void test_interthread_marshal_and_unmarshal()
|
static void test_interthread_marshal_and_unmarshal()
|
||||||
{
|
{
|
||||||
|
@ -403,6 +487,118 @@ static void test_marshal_proxy_apartment_shutdown()
|
||||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tests that proxies are released when the containing mta apartment is destroyed */
|
||||||
|
static void test_marshal_proxy_mta_apartment_shutdown()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IStream *pStream = NULL;
|
||||||
|
IUnknown *pProxy = NULL;
|
||||||
|
DWORD tid;
|
||||||
|
HANDLE thread;
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
|
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||||
|
|
||||||
|
cLocks = 0;
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||||
|
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||||
|
tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
|
||||||
|
ok_ole_success(hr, CoReleaseMarshalData);
|
||||||
|
IStream_Release(pStream);
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
|
||||||
|
IUnknown_Release(pProxy);
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
|
||||||
|
end_host_object(tid, thread);
|
||||||
|
|
||||||
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ncu_params
|
||||||
|
{
|
||||||
|
LPSTREAM stream;
|
||||||
|
HANDLE marshal_event;
|
||||||
|
HANDLE unmarshal_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* helper for test_proxy_used_in_wrong_thread */
|
||||||
|
static DWORD CALLBACK no_couninitialize_proc(LPVOID p)
|
||||||
|
{
|
||||||
|
struct ncu_params *ncu_params = (struct ncu_params *)p;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||||
|
|
||||||
|
hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
|
||||||
|
ok_ole_success(hr, CoMarshalInterface);
|
||||||
|
|
||||||
|
SetEvent(ncu_params->marshal_event);
|
||||||
|
|
||||||
|
WaitForSingleObject(ncu_params->unmarshal_event, INFINITE);
|
||||||
|
|
||||||
|
/* die without calling CoUninitialize */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tests apartment that an apartment is released if the owning thread exits */
|
||||||
|
static void test_no_couninitialize()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IStream *pStream = NULL;
|
||||||
|
IUnknown *pProxy = NULL;
|
||||||
|
DWORD tid;
|
||||||
|
HANDLE thread;
|
||||||
|
struct ncu_params ncu_params;
|
||||||
|
|
||||||
|
cLocks = 0;
|
||||||
|
|
||||||
|
ncu_params.marshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
ncu_params.unmarshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||||
|
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||||
|
ncu_params.stream = pStream;
|
||||||
|
|
||||||
|
thread = CreateThread(NULL, 0, no_couninitialize_proc, &ncu_params, 0, &tid);
|
||||||
|
|
||||||
|
WaitForSingleObject(ncu_params.marshal_event, INFINITE);
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
|
||||||
|
ok_ole_success(hr, CoUnmarshalInterface);
|
||||||
|
IStream_Release(pStream);
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
SetEvent(ncu_params.unmarshal_event);
|
||||||
|
WaitForSingleObject(thread, INFINITE);
|
||||||
|
|
||||||
|
todo_wine { ok_no_locks(); }
|
||||||
|
|
||||||
|
CloseHandle(thread);
|
||||||
|
CloseHandle(ncu_params.marshal_event);
|
||||||
|
CloseHandle(ncu_params.unmarshal_event);
|
||||||
|
|
||||||
|
IUnknown_Release(pProxy);
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
}
|
||||||
|
|
||||||
/* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
|
/* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
|
||||||
static void test_tableweak_marshal_and_unmarshal_twice()
|
static void test_tableweak_marshal_and_unmarshal_twice()
|
||||||
{
|
{
|
||||||
|
@ -444,6 +640,96 @@ static void test_tableweak_marshal_and_unmarshal_twice()
|
||||||
end_host_object(tid, thread);
|
end_host_object(tid, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tests releasing after unmarshaling one object */
|
||||||
|
static void test_tableweak_marshal_releasedata1()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IStream *pStream = NULL;
|
||||||
|
IUnknown *pProxy1 = NULL;
|
||||||
|
IUnknown *pProxy2 = NULL;
|
||||||
|
DWORD tid;
|
||||||
|
HANDLE thread;
|
||||||
|
|
||||||
|
cLocks = 0;
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||||
|
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||||
|
tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
|
||||||
|
ok_ole_success(hr, CoUnmarshalInterface);
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
/* release the remaining reference on the object by calling
|
||||||
|
* CoReleaseMarshalData in the hosting thread */
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
release_host_object(tid);
|
||||||
|
|
||||||
|
todo_wine { ok_more_than_one_lock(); }
|
||||||
|
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
|
||||||
|
todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
|
||||||
|
IStream_Release(pStream);
|
||||||
|
|
||||||
|
todo_wine { ok_more_than_one_lock(); }
|
||||||
|
|
||||||
|
IUnknown_Release(pProxy1);
|
||||||
|
if (pProxy2)
|
||||||
|
IUnknown_Release(pProxy2);
|
||||||
|
|
||||||
|
/* this line is shows the difference between weak and strong table marshaling:
|
||||||
|
* weak has cLocks == 0
|
||||||
|
* strong has cLocks > 0 */
|
||||||
|
ok_no_locks();
|
||||||
|
|
||||||
|
end_host_object(tid, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tests releasing after unmarshaling one object */
|
||||||
|
static void test_tableweak_marshal_releasedata2()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IStream *pStream = NULL;
|
||||||
|
IUnknown *pProxy = NULL;
|
||||||
|
DWORD tid;
|
||||||
|
HANDLE thread;
|
||||||
|
|
||||||
|
cLocks = 0;
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||||
|
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||||
|
tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
/* release the remaining reference on the object by calling
|
||||||
|
* CoReleaseMarshalData in the hosting thread */
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
release_host_object(tid);
|
||||||
|
|
||||||
|
todo_wine
|
||||||
|
{
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
|
||||||
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
|
||||||
|
ok(hr == CO_E_OBJNOTREG,
|
||||||
|
"CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08lx instead\n",
|
||||||
|
hr);
|
||||||
|
IStream_Release(pStream);
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
}
|
||||||
|
|
||||||
|
end_host_object(tid, thread);
|
||||||
|
}
|
||||||
|
|
||||||
/* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
|
/* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
|
||||||
static void test_tablestrong_marshal_and_unmarshal_twice()
|
static void test_tablestrong_marshal_and_unmarshal_twice()
|
||||||
{
|
{
|
||||||
|
@ -892,6 +1178,40 @@ static void test_proxy_interfaces()
|
||||||
end_host_object(tid, thread);
|
end_host_object(tid, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_stubbuffer(REFIID riid)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IPSFactoryBuffer *psfb;
|
||||||
|
IRpcStubBuffer *stub;
|
||||||
|
ULONG refs;
|
||||||
|
CLSID clsid;
|
||||||
|
|
||||||
|
cLocks = 0;
|
||||||
|
|
||||||
|
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_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
|
||||||
|
ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
|
IRpcStubBuffer_Disconnect(stub);
|
||||||
|
|
||||||
|
ok_no_locks();
|
||||||
|
|
||||||
|
refs = IRpcStubBuffer_Release(stub);
|
||||||
|
ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
|
/* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1056,13 +1376,22 @@ START_TEST(marshal)
|
||||||
|
|
||||||
/* FIXME: test CoCreateInstanceEx */
|
/* FIXME: test CoCreateInstanceEx */
|
||||||
|
|
||||||
|
/* helper function tests */
|
||||||
|
test_CoGetPSClsid();
|
||||||
|
|
||||||
/* lifecycle management and marshaling tests */
|
/* lifecycle management and marshaling tests */
|
||||||
|
test_no_marshaler();
|
||||||
test_normal_marshal_and_release();
|
test_normal_marshal_and_release();
|
||||||
test_normal_marshal_and_unmarshal();
|
test_normal_marshal_and_unmarshal();
|
||||||
|
test_marshal_and_unmarshal_invalid();
|
||||||
test_interthread_marshal_and_unmarshal();
|
test_interthread_marshal_and_unmarshal();
|
||||||
test_marshal_stub_apartment_shutdown();
|
test_marshal_stub_apartment_shutdown();
|
||||||
test_marshal_proxy_apartment_shutdown();
|
test_marshal_proxy_apartment_shutdown();
|
||||||
|
test_marshal_proxy_mta_apartment_shutdown();
|
||||||
|
test_no_couninitialize();
|
||||||
test_tableweak_marshal_and_unmarshal_twice();
|
test_tableweak_marshal_and_unmarshal_twice();
|
||||||
|
test_tableweak_marshal_releasedata1();
|
||||||
|
test_tableweak_marshal_releasedata2();
|
||||||
test_tablestrong_marshal_and_unmarshal_twice();
|
test_tablestrong_marshal_and_unmarshal_twice();
|
||||||
test_lock_object_external();
|
test_lock_object_external();
|
||||||
test_disconnect_stub();
|
test_disconnect_stub();
|
||||||
|
@ -1072,7 +1401,7 @@ START_TEST(marshal)
|
||||||
test_message_filter();
|
test_message_filter();
|
||||||
test_bad_marshal_stream();
|
test_bad_marshal_stream();
|
||||||
test_proxy_interfaces();
|
test_proxy_interfaces();
|
||||||
/* FIXME: test custom marshaling */
|
test_stubbuffer(&IID_IClassFactory);
|
||||||
/* FIXME: test GIT */
|
/* FIXME: test GIT */
|
||||||
/* FIXME: test COM re-entrancy */
|
/* FIXME: test COM re-entrancy */
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "objbase.h"
|
#include "objbase.h"
|
||||||
|
#include "comcat.h"
|
||||||
|
|
||||||
#include "wine/test.h"
|
#include "wine/test.h"
|
||||||
|
|
||||||
|
@ -58,12 +59,93 @@ static void test_MkParseDisplayName()
|
||||||
IBindCtx_Release(pbc);
|
IBindCtx_Release(pbc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const BYTE expected_moniker_data[] =
|
||||||
|
{
|
||||||
|
0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
|
||||||
|
0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
|
||||||
|
0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
|
||||||
|
0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
|
||||||
|
0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
|
||||||
|
0x00,0x00,0x00,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LARGE_INTEGER llZero;
|
||||||
|
|
||||||
|
static void test_class_moniker()
|
||||||
|
{
|
||||||
|
IStream * stream;
|
||||||
|
IMoniker * moniker;
|
||||||
|
HRESULT hr;
|
||||||
|
HGLOBAL hglobal;
|
||||||
|
LPBYTE moniker_data;
|
||||||
|
DWORD moniker_size;
|
||||||
|
DWORD i;
|
||||||
|
BOOL same = TRUE;
|
||||||
|
|
||||||
|
hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);
|
||||||
|
todo_wine { ok_ole_success(hr, CreateClassMoniker); }
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
|
||||||
|
|
||||||
|
hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
|
||||||
|
todo_wine { ok_ole_success(hr, CoMarshalInterface); }
|
||||||
|
|
||||||
|
hr = GetHGlobalFromStream(stream, &hglobal);
|
||||||
|
ok_ole_success(hr, GetHGlobalFromStream);
|
||||||
|
|
||||||
|
moniker_size = GlobalSize(hglobal);
|
||||||
|
|
||||||
|
moniker_data = GlobalLock(hglobal);
|
||||||
|
|
||||||
|
/* first check we have the right amount of data */
|
||||||
|
todo_wine {
|
||||||
|
ok(moniker_size == sizeof(expected_moniker_data),
|
||||||
|
"Size of marshaled data differs (expected %d, actual %ld)\n",
|
||||||
|
sizeof(expected_moniker_data), moniker_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* then do a byte-by-byte comparison */
|
||||||
|
for (i = 0; i < min(moniker_size, sizeof(expected_moniker_data)); i++)
|
||||||
|
{
|
||||||
|
if (expected_moniker_data[i] != moniker_data[i])
|
||||||
|
{
|
||||||
|
same = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(same, "Marshaled data differs\n");
|
||||||
|
if (!same)
|
||||||
|
{
|
||||||
|
trace("Dumping marshaled moniker data:\n");
|
||||||
|
for (i = 0; i < moniker_size; i++)
|
||||||
|
{
|
||||||
|
trace("0x%02x,", moniker_data[i]);
|
||||||
|
if (i % 8 == 7) trace("\n");
|
||||||
|
if (i % 8 == 0) trace(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalUnlock(hglobal);
|
||||||
|
|
||||||
|
IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoReleaseMarshalData(stream);
|
||||||
|
todo_wine { ok_ole_success(hr, CoReleaseMarshalData); }
|
||||||
|
|
||||||
|
IStream_Release(stream);
|
||||||
|
if (moniker) IMoniker_Release(moniker);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(moniker)
|
START_TEST(moniker)
|
||||||
{
|
{
|
||||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||||
|
|
||||||
/* FIXME: test moniker creation funcs and parsing other moniker formats */
|
|
||||||
test_MkParseDisplayName();
|
test_MkParseDisplayName();
|
||||||
|
test_class_moniker();
|
||||||
|
/* FIXME: test moniker creation funcs and parsing other moniker formats */
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue