Module: wine Branch: master Commit: a06f568a2a356a979c9371930023c1032e34e9b8 URL: http://source.winehq.org/git/wine.git/?a=commit;h=a06f568a2a356a979c93719300...
Author: Andrey Turkin andrey.turkin@gmail.com Date: Sun Jan 18 17:17:45 2009 +0300
ole32: Add CoGetCallContext and CoSwitchCallContext implementations.
---
dlls/ole32/compobj.c | 42 ++++++++++++++++- dlls/ole32/compobj_private.h | 1 + dlls/ole32/ole32.spec | 2 +- dlls/ole32/tests/compobj.c | 103 ++++++++++++++++++++++++++++++++++++++++++ include/objbase.h | 1 + 5 files changed, 145 insertions(+), 4 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 9501473..b291db4 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -3352,10 +3352,46 @@ HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) */ HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv) { - FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv); + struct oletls *info = COM_CurrentInfo();
- *ppv = NULL; - return E_NOINTERFACE; + TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); + + if (!info) + return E_OUTOFMEMORY; + + if (!info->call_state) + return RPC_E_CALL_COMPLETE; + + return IUnknown_QueryInterface(info->call_state, riid, ppv); +} + +/*********************************************************************** + * CoSwitchCallContext [OLE32.@] + * + * Switches the context of the currently executing server call in the current + * thread. + * + * PARAMS + * pObject [I] Pointer to new context object + * ppOldObject [O] Pointer to memory that will receive old context object pointer + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject) +{ + struct oletls *info = COM_CurrentInfo(); + + TRACE("(%p, %p)\n", pObject, ppOldObject); + + if (!info) + return E_OUTOFMEMORY; + + *ppOldObject = info->call_state; + info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */ + + return S_OK; }
/*********************************************************************** diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 3c3e96d..8f2cc2c 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -181,6 +181,7 @@ struct oletls GUID causality_id; /* unique identifier for each COM call */ LONG pending_call_count_client; /* number of client calls pending */ LONG pending_call_count_server; /* number of server calls pending */ + IUnknown *call_state; /* current call context */ };
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index 49ff1d3..7d69bd8 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -73,7 +73,7 @@ @ stdcall CoSetProxyBlanket(ptr long long wstr long long ptr long) @ stdcall CoSetState(ptr) @ stdcall CoSuspendClassObjects() -@ stub CoSwitchCallContext +@ stdcall CoSwitchCallContext(ptr ptr) @ stdcall CoTaskMemAlloc(long) @ stdcall CoTaskMemFree(ptr) @ stdcall CoTaskMemRealloc(ptr long) diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 63891b7..046b91a 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -37,6 +37,7 @@ /* functions that are not present on all versions of Windows */ HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv); +HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppOldObject);
#define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr) #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks) @@ -1039,6 +1040,106 @@ static void test_CoGetObjectContext(void) CoUninitialize(); }
+typedef struct { + const IUnknownVtbl *lpVtbl; + LONG refs; +} Test_CallContext; + +static HRESULT WINAPI Test_CallContext_QueryInterface( + IUnknown *iface, + REFIID riid, + LPVOID *ppvObj) +{ + if (ppvObj == NULL) return E_POINTER; + + if (IsEqualGUID(riid, &IID_IUnknown)) + { + *ppvObj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + *ppvObj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface) +{ + Test_CallContext *This = (Test_CallContext*)iface; + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI Test_CallContext_Release(IUnknown *iface) +{ + Test_CallContext *This = (Test_CallContext*)iface; + ULONG refs = InterlockedDecrement(&This->refs); + if (!refs) + HeapFree(GetProcessHeap(), 0, This); + return refs; +} + +static const IUnknownVtbl TestCallContext_Vtbl = +{ + Test_CallContext_QueryInterface, + Test_CallContext_AddRef, + Test_CallContext_Release +}; + +static void test_CoGetCallContext(void) +{ + HRESULT hr; + ULONG refs; + IUnknown *pUnk; + IUnknown *test_object; + + if (!pCoSwitchCallContext) + { + skip("CoSwitchCallContext not present\n"); + return; + } + + CoInitialize(NULL); + + test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext)); + ((Test_CallContext*)test_object)->lpVtbl = &TestCallContext_Vtbl; + ((Test_CallContext*)test_object)->refs = 1; + + hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk); + ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr); + + pUnk = (IUnknown*)0xdeadbeef; + hr = pCoSwitchCallContext(test_object, &pUnk); + ok_ole_success(hr, "CoSwitchCallContext"); + ok(pUnk == NULL, "expected NULL, got %p\n", pUnk); + refs = IUnknown_AddRef(test_object); + ok(refs == 2, "Expected refcount 2, got %d\n", refs); + IUnknown_Release(test_object); + + pUnk = (IUnknown*)0xdeadbeef; + hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk); + ok_ole_success(hr, "CoGetCallContext"); + ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk); + refs = IUnknown_AddRef(test_object); + ok(refs == 3, "Expected refcount 3, got %d\n", refs); + IUnknown_Release(test_object); + IUnknown_Release(pUnk); + + pUnk = (IUnknown*)0xdeadbeef; + hr = pCoSwitchCallContext(NULL, &pUnk); + ok_ole_success(hr, "CoSwitchCallContext"); + ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk); + refs = IUnknown_AddRef(test_object); + ok(refs == 2, "Expected refcount 2, got %d\n", refs); + IUnknown_Release(test_object); + + hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk); + ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr); + + IUnknown_Release(test_object); + + CoUninitialize(); +} + static void test_CoInitializeEx(void) { HRESULT hr; @@ -1064,6 +1165,7 @@ START_TEST(compobj) { HMODULE hOle32 = GetModuleHandle("ole32"); pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext"); + pCoSwitchCallContext = (void*)GetProcAddress(hOle32, "CoSwitchCallContext"); if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) { trace("You need DCOM95 installed to run this test\n"); @@ -1088,5 +1190,6 @@ START_TEST(compobj) test_registered_object_thread_affinity(); test_CoFreeUnusedLibraries(); test_CoGetObjectContext(); + test_CoGetCallContext(); test_CoInitializeEx(); } diff --git a/include/objbase.h b/include/objbase.h index 9f606c0..7e72fad 100644 --- a/include/objbase.h +++ b/include/objbase.h @@ -391,6 +391,7 @@ BOOL WINAPI CoIsHandlerConnected(LPUNKNOWN pUnk); /* security */ HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, SOLE_AUTHENTICATION_SERVICE* asAuthSvc, void* pReserved1, DWORD dwAuthnLevel, DWORD dwImpLevel, void* pReserved2, DWORD dwCapabilities, void* pReserved3); HRESULT WINAPI CoGetCallContext(REFIID riid, void** ppInterface); +HRESULT WINAPI CoSwitchCallContext(IUnknown *pContext, IUnknown **ppOldContext); HRESULT WINAPI CoQueryAuthenticationServices(DWORD* pcAuthSvc, SOLE_AUTHENTICATION_SERVICE** asAuthSvc);
HRESULT WINAPI CoQueryProxyBlanket(IUnknown* pProxy, DWORD* pwAuthnSvc, DWORD* pAuthzSvc, OLECHAR** pServerPrincName, DWORD* pAuthnLevel, DWORD* pImpLevel, RPC_AUTH_IDENTITY_HANDLE* pAuthInfo, DWORD* pCapabilities);