Andrey Turkin : ole32: Add CoGetCallContext and CoSwitchCallContext implementations.
Alexandre Julliard
julliard at winehq.org
Mon Jan 19 08:59:06 CST 2009
Module: wine
Branch: master
Commit: a06f568a2a356a979c9371930023c1032e34e9b8
URL: http://source.winehq.org/git/wine.git/?a=commit;h=a06f568a2a356a979c9371930023c1032e34e9b8
Author: Andrey Turkin <andrey.turkin at 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);
More information about the wine-cvs
mailing list