1c2c66affSColin Finck /*
2c2c66affSColin Finck  * NDR data marshalling
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2006 Mike McCormack (for CodeWeavers)
5c2c66affSColin Finck  * Copyright 2006-2007 Robert Shearman (for CodeWeavers)
6c2c66affSColin Finck  *
7c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
8c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
9c2c66affSColin Finck  * License as published by the Free Software Foundation; either
10c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
11c2c66affSColin Finck  *
12c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
13c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15c2c66affSColin Finck  * Lesser General Public License for more details.
16c2c66affSColin Finck  *
17c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
18c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
19c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20c2c66affSColin Finck  */
21c2c66affSColin Finck 
22*87a48c83SAmine Khaldi #include "ndr_misc.h"
23*87a48c83SAmine Khaldi #include "rpc_assoc.h"
24*87a48c83SAmine Khaldi #include "rpcndr.h"
25*87a48c83SAmine Khaldi 
26*87a48c83SAmine Khaldi #include "wine/debug.h"
27*87a48c83SAmine Khaldi #include "wine/list.h"
28c2c66affSColin Finck 
29c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(ole);
30c2c66affSColin Finck 
31c2c66affSColin Finck #define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
32c2c66affSColin Finck 
33c2c66affSColin Finck typedef struct ndr_context_handle
34c2c66affSColin Finck {
35c2c66affSColin Finck     ULONG      attributes;
36c2c66affSColin Finck     GUID       uuid;
37c2c66affSColin Finck } ndr_context_handle;
38c2c66affSColin Finck 
39c2c66affSColin Finck struct context_handle_entry
40c2c66affSColin Finck {
41c2c66affSColin Finck     struct list entry;
42c2c66affSColin Finck     DWORD magic;
43c2c66affSColin Finck     RPC_BINDING_HANDLE handle;
44c2c66affSColin Finck     ndr_context_handle wire_data;
45c2c66affSColin Finck };
46c2c66affSColin Finck 
47c2c66affSColin Finck static struct list context_handle_list = LIST_INIT(context_handle_list);
48c2c66affSColin Finck 
49c2c66affSColin Finck static CRITICAL_SECTION ndr_context_cs;
50c2c66affSColin Finck static CRITICAL_SECTION_DEBUG ndr_context_debug =
51c2c66affSColin Finck {
52c2c66affSColin Finck     0, 0, &ndr_context_cs,
53c2c66affSColin Finck     { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList },
54c2c66affSColin Finck       0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") }
55c2c66affSColin Finck };
56c2c66affSColin Finck static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 };
57c2c66affSColin Finck 
get_context_entry(NDR_CCONTEXT CContext)58c2c66affSColin Finck static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext)
59c2c66affSColin Finck {
60c2c66affSColin Finck     struct context_handle_entry *che = CContext;
61c2c66affSColin Finck 
62c2c66affSColin Finck     if (che->magic != NDR_CONTEXT_HANDLE_MAGIC)
63c2c66affSColin Finck         return NULL;
64c2c66affSColin Finck     return che;
65c2c66affSColin Finck }
66c2c66affSColin Finck 
context_entry_from_guid(LPCGUID uuid)67c2c66affSColin Finck static struct context_handle_entry *context_entry_from_guid(LPCGUID uuid)
68c2c66affSColin Finck {
69c2c66affSColin Finck     struct context_handle_entry *che;
70c2c66affSColin Finck     LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry)
71c2c66affSColin Finck         if (IsEqualGUID(&che->wire_data.uuid, uuid))
72c2c66affSColin Finck             return che;
73c2c66affSColin Finck     return NULL;
74c2c66affSColin Finck }
75c2c66affSColin Finck 
NDRCContextBinding(NDR_CCONTEXT CContext)76c2c66affSColin Finck RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext)
77c2c66affSColin Finck {
78c2c66affSColin Finck     struct context_handle_entry *che;
79c2c66affSColin Finck     RPC_BINDING_HANDLE handle = NULL;
80c2c66affSColin Finck 
81c2c66affSColin Finck     TRACE("%p\n", CContext);
82c2c66affSColin Finck 
83c2c66affSColin Finck     EnterCriticalSection(&ndr_context_cs);
84c2c66affSColin Finck     che = get_context_entry(CContext);
85c2c66affSColin Finck     if (che)
86c2c66affSColin Finck         handle = che->handle;
87c2c66affSColin Finck     LeaveCriticalSection(&ndr_context_cs);
88c2c66affSColin Finck 
89c2c66affSColin Finck     if (!handle)
90c2c66affSColin Finck     {
91c2c66affSColin Finck         ERR("invalid handle %p\n", CContext);
92c2c66affSColin Finck         RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
93c2c66affSColin Finck     }
94c2c66affSColin Finck     return handle;
95c2c66affSColin Finck }
96c2c66affSColin Finck 
NDRCContextMarshall(NDR_CCONTEXT CContext,void * pBuff)97c2c66affSColin Finck void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
98c2c66affSColin Finck {
99c2c66affSColin Finck     struct context_handle_entry *che;
100c2c66affSColin Finck 
101c2c66affSColin Finck     TRACE("%p %p\n", CContext, pBuff);
102c2c66affSColin Finck 
103c2c66affSColin Finck     if (CContext)
104c2c66affSColin Finck     {
105c2c66affSColin Finck         EnterCriticalSection(&ndr_context_cs);
106c2c66affSColin Finck         che = get_context_entry(CContext);
107c2c66affSColin Finck         memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
108c2c66affSColin Finck         LeaveCriticalSection(&ndr_context_cs);
109c2c66affSColin Finck     }
110c2c66affSColin Finck     else
111c2c66affSColin Finck     {
112c2c66affSColin Finck         ndr_context_handle *wire_data = pBuff;
113c2c66affSColin Finck         wire_data->attributes = 0;
114c2c66affSColin Finck         wire_data->uuid = GUID_NULL;
115c2c66affSColin Finck     }
116c2c66affSColin Finck }
117c2c66affSColin Finck 
118c2c66affSColin Finck /***********************************************************************
119c2c66affSColin Finck  *           RpcSmDestroyClientContext [RPCRT4.@]
120c2c66affSColin Finck  */
RpcSmDestroyClientContext(void ** ContextHandle)121c2c66affSColin Finck RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
122c2c66affSColin Finck {
123c2c66affSColin Finck     RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
124c2c66affSColin Finck     struct context_handle_entry *che = NULL;
125c2c66affSColin Finck 
126c2c66affSColin Finck     TRACE("(%p)\n", ContextHandle);
127c2c66affSColin Finck 
128c2c66affSColin Finck     EnterCriticalSection(&ndr_context_cs);
129c2c66affSColin Finck     che = get_context_entry(*ContextHandle);
130c2c66affSColin Finck     *ContextHandle = NULL;
131c2c66affSColin Finck     if (che)
132c2c66affSColin Finck     {
133c2c66affSColin Finck         status = RPC_S_OK;
134c2c66affSColin Finck         list_remove(&che->entry);
135c2c66affSColin Finck     }
136c2c66affSColin Finck 
137c2c66affSColin Finck     LeaveCriticalSection(&ndr_context_cs);
138c2c66affSColin Finck 
139c2c66affSColin Finck     if (che)
140c2c66affSColin Finck     {
141c2c66affSColin Finck         RpcBindingFree(&che->handle);
142c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, che);
143c2c66affSColin Finck     }
144c2c66affSColin Finck 
145c2c66affSColin Finck     return status;
146c2c66affSColin Finck }
147c2c66affSColin Finck 
148c2c66affSColin Finck /***********************************************************************
149c2c66affSColin Finck  *           RpcSsDestroyClientContext [RPCRT4.@]
150c2c66affSColin Finck  */
RpcSsDestroyClientContext(void ** ContextHandle)151c2c66affSColin Finck void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
152c2c66affSColin Finck {
153c2c66affSColin Finck     RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
154c2c66affSColin Finck     if (status != RPC_S_OK)
155c2c66affSColin Finck         RpcRaiseException(status);
156c2c66affSColin Finck }
157c2c66affSColin Finck 
158c2c66affSColin Finck /***********************************************************************
159c2c66affSColin Finck  *           RpcSsDontSerializeContext [RPCRT4.@]
160c2c66affSColin Finck  */
RpcSsDontSerializeContext(void)161c2c66affSColin Finck  void WINAPI RpcSsDontSerializeContext(void)
162c2c66affSColin Finck {
163c2c66affSColin Finck     FIXME("stub\n");
164c2c66affSColin Finck }
165c2c66affSColin Finck 
ndr_update_context_handle(NDR_CCONTEXT * CContext,RPC_BINDING_HANDLE hBinding,const ndr_context_handle * chi)166c2c66affSColin Finck static RPC_STATUS ndr_update_context_handle(NDR_CCONTEXT *CContext,
167c2c66affSColin Finck                                       RPC_BINDING_HANDLE hBinding,
168c2c66affSColin Finck                                       const ndr_context_handle *chi)
169c2c66affSColin Finck {
170c2c66affSColin Finck     struct context_handle_entry *che = NULL;
171c2c66affSColin Finck 
172c2c66affSColin Finck     /* a null UUID means we should free the context handle */
173c2c66affSColin Finck     if (IsEqualGUID(&chi->uuid, &GUID_NULL))
174c2c66affSColin Finck     {
175c2c66affSColin Finck         if (*CContext)
176c2c66affSColin Finck         {
177c2c66affSColin Finck             che = get_context_entry(*CContext);
178c2c66affSColin Finck             if (!che)
179c2c66affSColin Finck                 return RPC_X_SS_CONTEXT_MISMATCH;
180c2c66affSColin Finck             list_remove(&che->entry);
181c2c66affSColin Finck             RpcBindingFree(&che->handle);
182c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, che);
183c2c66affSColin Finck             che = NULL;
184c2c66affSColin Finck         }
185c2c66affSColin Finck     }
186c2c66affSColin Finck     /* if there's no existing entry matching the GUID, allocate one */
187c2c66affSColin Finck     else if (!(che = context_entry_from_guid(&chi->uuid)))
188c2c66affSColin Finck     {
189c2c66affSColin Finck         che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
190c2c66affSColin Finck         if (!che)
191c2c66affSColin Finck             return RPC_X_NO_MEMORY;
192c2c66affSColin Finck         che->magic = NDR_CONTEXT_HANDLE_MAGIC;
193c2c66affSColin Finck         RpcBindingCopy(hBinding, &che->handle);
194c2c66affSColin Finck         list_add_tail(&context_handle_list, &che->entry);
195c2c66affSColin Finck         che->wire_data = *chi;
196c2c66affSColin Finck     }
197c2c66affSColin Finck 
198c2c66affSColin Finck     *CContext = che;
199c2c66affSColin Finck 
200c2c66affSColin Finck     return RPC_S_OK;
201c2c66affSColin Finck }
202c2c66affSColin Finck 
203c2c66affSColin Finck /***********************************************************************
204c2c66affSColin Finck  *           NDRCContextUnmarshall [RPCRT4.@]
205c2c66affSColin Finck  */
NDRCContextUnmarshall(NDR_CCONTEXT * CContext,RPC_BINDING_HANDLE hBinding,void * pBuff,ULONG DataRepresentation)206c2c66affSColin Finck void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
207c2c66affSColin Finck                                   RPC_BINDING_HANDLE hBinding,
208c2c66affSColin Finck                                   void *pBuff, ULONG DataRepresentation)
209c2c66affSColin Finck {
210c2c66affSColin Finck     RPC_STATUS status;
211c2c66affSColin Finck 
212c2c66affSColin Finck     TRACE("*%p=(%p) %p %p %08x\n",
213c2c66affSColin Finck           CContext, *CContext, hBinding, pBuff, DataRepresentation);
214c2c66affSColin Finck 
215c2c66affSColin Finck     EnterCriticalSection(&ndr_context_cs);
216c2c66affSColin Finck     status = ndr_update_context_handle(CContext, hBinding, pBuff);
217c2c66affSColin Finck     LeaveCriticalSection(&ndr_context_cs);
218c2c66affSColin Finck     if (status)
219c2c66affSColin Finck         RpcRaiseException(status);
220c2c66affSColin Finck }
221c2c66affSColin Finck 
222c2c66affSColin Finck /***********************************************************************
223c2c66affSColin Finck  *           NDRSContextMarshall [RPCRT4.@]
224c2c66affSColin Finck  */
NDRSContextMarshall(NDR_SCONTEXT SContext,void * pBuff,NDR_RUNDOWN userRunDownIn)225c2c66affSColin Finck void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
226c2c66affSColin Finck                                void *pBuff,
227c2c66affSColin Finck                                NDR_RUNDOWN userRunDownIn)
228c2c66affSColin Finck {
229c2c66affSColin Finck     TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
230c2c66affSColin Finck     NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff,
231c2c66affSColin Finck                          userRunDownIn, NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
232c2c66affSColin Finck }
233c2c66affSColin Finck 
234c2c66affSColin Finck /***********************************************************************
235c2c66affSColin Finck  *           NDRSContextMarshallEx [RPCRT4.@]
236c2c66affSColin Finck  */
NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,NDR_SCONTEXT SContext,void * pBuff,NDR_RUNDOWN userRunDownIn)237c2c66affSColin Finck void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
238c2c66affSColin Finck                                   NDR_SCONTEXT SContext,
239c2c66affSColin Finck                                   void *pBuff,
240c2c66affSColin Finck                                   NDR_RUNDOWN userRunDownIn)
241c2c66affSColin Finck {
242c2c66affSColin Finck     TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
243c2c66affSColin Finck     NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL,
244c2c66affSColin Finck                          RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
245c2c66affSColin Finck }
246c2c66affSColin Finck 
247c2c66affSColin Finck /***********************************************************************
248c2c66affSColin Finck  *           NDRSContextMarshall2 [RPCRT4.@]
249c2c66affSColin Finck  */
NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,NDR_SCONTEXT SContext,void * pBuff,NDR_RUNDOWN userRunDownIn,void * CtxGuard,ULONG Flags)250c2c66affSColin Finck void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
251c2c66affSColin Finck                                  NDR_SCONTEXT SContext,
252c2c66affSColin Finck                                  void *pBuff,
253c2c66affSColin Finck                                  NDR_RUNDOWN userRunDownIn,
254c2c66affSColin Finck                                  void *CtxGuard, ULONG Flags)
255c2c66affSColin Finck {
256c2c66affSColin Finck     RpcBinding *binding = hBinding;
257c2c66affSColin Finck     RPC_STATUS status;
258c2c66affSColin Finck     ndr_context_handle *ndr = pBuff;
259c2c66affSColin Finck 
260c2c66affSColin Finck     TRACE("(%p %p %p %p %p %u)\n",
261c2c66affSColin Finck           hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
262c2c66affSColin Finck 
263c2c66affSColin Finck     if (!binding->server || !binding->Assoc)
264c2c66affSColin Finck         RpcRaiseException(RPC_S_INVALID_BINDING);
265c2c66affSColin Finck 
266c2c66affSColin Finck     if (SContext->userContext)
267c2c66affSColin Finck     {
268c2c66affSColin Finck         status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
269c2c66affSColin Finck         if (status != RPC_S_OK)
270c2c66affSColin Finck             RpcRaiseException(status);
271c2c66affSColin Finck         ndr->attributes = 0;
272c2c66affSColin Finck         RpcContextHandle_GetUuid(SContext, &ndr->uuid);
273c2c66affSColin Finck 
274c2c66affSColin Finck         RPCRT4_RemoveThreadContextHandle(SContext);
275c2c66affSColin Finck         RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
276c2c66affSColin Finck     }
277c2c66affSColin Finck     else
278c2c66affSColin Finck     {
279c2c66affSColin Finck         if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
280c2c66affSColin Finck             RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
281c2c66affSColin Finck         memset(ndr, 0, sizeof(*ndr));
282c2c66affSColin Finck 
283c2c66affSColin Finck         RPCRT4_RemoveThreadContextHandle(SContext);
284c2c66affSColin Finck         /* Note: release the context handle twice in this case to release
285c2c66affSColin Finck          * one ref being kept around for the data and one ref for the
286c2c66affSColin Finck          * unmarshall/marshall sequence */
287c2c66affSColin Finck         if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE))
288c2c66affSColin Finck             return; /* this is to cope with the case of the data not being valid
289c2c66affSColin Finck                      * before and so not having a further reference */
290c2c66affSColin Finck         RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE);
291c2c66affSColin Finck     }
292c2c66affSColin Finck }
293c2c66affSColin Finck 
294c2c66affSColin Finck /***********************************************************************
295c2c66affSColin Finck  *           NDRSContextUnmarshall [RPCRT4.@]
296c2c66affSColin Finck  */
NDRSContextUnmarshall(void * pBuff,ULONG DataRepresentation)297c2c66affSColin Finck NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
298c2c66affSColin Finck                                           ULONG DataRepresentation)
299c2c66affSColin Finck {
300c2c66affSColin Finck     TRACE("(%p %08x)\n", pBuff, DataRepresentation);
301c2c66affSColin Finck     return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff,
302c2c66affSColin Finck                                   DataRepresentation, NULL,
303c2c66affSColin Finck                                   RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
304c2c66affSColin Finck }
305c2c66affSColin Finck 
306c2c66affSColin Finck /***********************************************************************
307c2c66affSColin Finck  *           NDRSContextUnmarshallEx [RPCRT4.@]
308c2c66affSColin Finck  */
NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,void * pBuff,ULONG DataRepresentation)309c2c66affSColin Finck NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
310c2c66affSColin Finck                                             void *pBuff,
311c2c66affSColin Finck                                             ULONG DataRepresentation)
312c2c66affSColin Finck {
313c2c66affSColin Finck     TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
314c2c66affSColin Finck     return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL,
315c2c66affSColin Finck                                   RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
316c2c66affSColin Finck }
317c2c66affSColin Finck 
318c2c66affSColin Finck /***********************************************************************
319c2c66affSColin Finck  *           NDRSContextUnmarshall2 [RPCRT4.@]
320c2c66affSColin Finck  */
NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,void * pBuff,ULONG DataRepresentation,void * CtxGuard,ULONG Flags)321c2c66affSColin Finck NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
322c2c66affSColin Finck                                            void *pBuff,
323c2c66affSColin Finck                                            ULONG DataRepresentation,
324c2c66affSColin Finck                                            void *CtxGuard, ULONG Flags)
325c2c66affSColin Finck {
326c2c66affSColin Finck     RpcBinding *binding = hBinding;
327c2c66affSColin Finck     NDR_SCONTEXT SContext;
328c2c66affSColin Finck     RPC_STATUS status;
329c2c66affSColin Finck     const ndr_context_handle *context_ndr = pBuff;
330c2c66affSColin Finck 
331c2c66affSColin Finck     TRACE("(%p %p %08x %p %u)\n",
332c2c66affSColin Finck           hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
333c2c66affSColin Finck 
334c2c66affSColin Finck     if (!binding->server || !binding->Assoc)
335c2c66affSColin Finck         RpcRaiseException(RPC_S_INVALID_BINDING);
336c2c66affSColin Finck 
337c2c66affSColin Finck     if (!pBuff || (!context_ndr->attributes &&
338c2c66affSColin Finck                    UuidIsNil((UUID *)&context_ndr->uuid, &status)))
339c2c66affSColin Finck         status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
340c2c66affSColin Finck                                                       &SContext);
341c2c66affSColin Finck     else
342c2c66affSColin Finck     {
343c2c66affSColin Finck         if (context_ndr->attributes)
344c2c66affSColin Finck         {
345c2c66affSColin Finck             ERR("non-null attributes 0x%x\n", context_ndr->attributes);
346c2c66affSColin Finck             status = RPC_X_SS_CONTEXT_MISMATCH;
347c2c66affSColin Finck         }
348c2c66affSColin Finck         else
349c2c66affSColin Finck             status = RpcServerAssoc_FindContextHandle(binding->Assoc,
350c2c66affSColin Finck                                                       &context_ndr->uuid,
351c2c66affSColin Finck                                                       CtxGuard, Flags,
352c2c66affSColin Finck                                                       &SContext);
353c2c66affSColin Finck     }
354c2c66affSColin Finck 
355c2c66affSColin Finck     if (status != RPC_S_OK)
356c2c66affSColin Finck         RpcRaiseException(status);
357c2c66affSColin Finck 
358c2c66affSColin Finck     RPCRT4_PushThreadContextHandle(SContext);
359c2c66affSColin Finck     return SContext;
360c2c66affSColin Finck }
361