rpcrt4: Retrieve the stubless information for the thunks directly from the virtual...
[wine] / dlls / rpcrt4 / cstub.c
1 /*
2  * COM stub (CStdStubBuffer) implementation
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25
26 #define COBJMACROS
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "excpt.h"
32
33 #include "objbase.h"
34 #include "rpcproxy.h"
35
36 #include "wine/debug.h"
37 #include "wine/exception.h"
38
39 #include "cpsf.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42
43 #define STUB_HEADER(This) (((const CInterfaceStubHeader*)((This)->lpVtbl))[-1])
44
45 static LONG WINAPI stub_filter(EXCEPTION_POINTERS *eptr)
46 {
47     if (eptr->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
48         return EXCEPTION_CONTINUE_SEARCH;
49     return EXCEPTION_EXECUTE_HANDLER;
50 }
51
52 typedef struct
53 {
54     IUnknownVtbl *base_obj;
55     IRpcStubBuffer *base_stub;
56     CStdStubBuffer stub_buffer;
57 } cstdstubbuffer_delegating_t;
58
59 static inline cstdstubbuffer_delegating_t *impl_from_delegating( IRpcStubBuffer *iface )
60 {
61     return (cstdstubbuffer_delegating_t*)((char *)iface - FIELD_OFFSET(cstdstubbuffer_delegating_t, stub_buffer));
62 }
63
64 HRESULT CStdStubBuffer_Construct(REFIID riid,
65                                  LPUNKNOWN pUnkServer,
66                                  PCInterfaceName name,
67                                  CInterfaceStubVtbl *vtbl,
68                                  LPPSFACTORYBUFFER pPSFactory,
69                                  LPRPCSTUBBUFFER *ppStub)
70 {
71   CStdStubBuffer *This;
72   IUnknown *pvServer;
73   HRESULT r;
74   TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name);
75   TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid));
76   TRACE("vtbl=%p\n", &vtbl->Vtbl);
77
78   if (!IsEqualGUID(vtbl->header.piid, riid)) {
79     ERR("IID mismatch during stub creation\n");
80     return RPC_E_UNEXPECTED;
81   }
82
83   r = IUnknown_QueryInterface(pUnkServer, riid, (void**)&pvServer);
84   if(FAILED(r))
85     return r;
86
87   This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CStdStubBuffer));
88   if (!This) {
89     IUnknown_Release(pvServer);
90     return E_OUTOFMEMORY;
91   }
92
93   This->lpVtbl = &vtbl->Vtbl;
94   This->RefCount = 1;
95   This->pvServerObject = pvServer;
96   This->pPSFactory = pPSFactory;
97   *ppStub = (LPRPCSTUBBUFFER)This;
98
99   IPSFactoryBuffer_AddRef(pPSFactory);
100   return S_OK;
101 }
102
103 static CRITICAL_SECTION delegating_vtbl_section;
104 static CRITICAL_SECTION_DEBUG critsect_debug =
105 {
106     0, 0, &delegating_vtbl_section,
107     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
108       0, 0, { (DWORD_PTR)(__FILE__ ": delegating_vtbl_section") }
109 };
110 static CRITICAL_SECTION delegating_vtbl_section = { &critsect_debug, -1, 0, 0, 0, 0 };
111
112 typedef struct
113 {
114     DWORD ref;
115     DWORD size;
116     IUnknownVtbl vtbl;
117     /* remaining entries in vtbl */
118 } ref_counted_vtbl;
119
120 static ref_counted_vtbl *current_vtbl;
121
122
123 static HRESULT WINAPI delegating_QueryInterface(IUnknown *pUnk, REFIID iid, void **ppv)
124 {
125     *ppv = pUnk;
126     return S_OK;
127 }
128
129 static ULONG WINAPI delegating_AddRef(IUnknown *pUnk)
130 {
131     return 1;
132 }
133
134 static ULONG WINAPI delegating_Release(IUnknown *pUnk)
135 {
136     return 1;
137 }
138
139 #if defined(__i386__)
140
141 /* The idea here is to replace the first param on the stack
142    ie. This (which will point to cstdstubbuffer_delegating_t)
143    with This->stub_buffer.pvServerObject and then jump to the
144    relevant offset in This->stub_buffer.pvServerObject's vtbl.
145 */
146 #include "pshpack1.h"
147 typedef struct {
148     DWORD mov1;    /* mov 0x4(%esp), %eax      8b 44 24 04 */
149     WORD mov2;     /* mov 0x10(%eax), %eax     8b 40 */
150     BYTE sixteen;  /*                          10   */
151     DWORD mov3;    /* mov %eax, 0x4(%esp)      89 44 24 04 */
152     WORD mov4;     /* mov (%eax), %eax         8b 00 */
153     WORD mov5;     /* mov offset(%eax), %eax   8b 80 */
154     DWORD offset;  /*                          xx xx xx xx */
155     WORD jmp;      /* jmp *%eax                ff e0 */
156     BYTE pad[3];   /* lea 0x0(%esi), %esi      8d 76 00 */
157 } vtbl_method_t;
158 #include "poppack.h"
159
160 #define BLOCK_SIZE 1024
161 #define MAX_BLOCKS 64  /* 64k methods should be enough for anybody */
162
163 static const vtbl_method_t *method_blocks[MAX_BLOCKS];
164
165 static const vtbl_method_t *allocate_block( unsigned int num )
166 {
167     unsigned int i;
168     vtbl_method_t *prev, *block;
169
170     block = VirtualAlloc( NULL, BLOCK_SIZE * sizeof(*block),
171                           MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
172     if (!block) return NULL;
173
174     for (i = 0; i < BLOCK_SIZE; i++)
175     {
176         block[i].mov1 = 0x0424448b;
177         block[i].mov2 = 0x408b;
178         block[i].sixteen = 0x10;
179         block[i].mov3 = 0x04244489;
180         block[i].mov4 = 0x008b;
181         block[i].mov5 = 0x808b;
182         block[i].offset = (BLOCK_SIZE * num + i + 3) << 2;
183         block[i].jmp = 0xe0ff;
184         block[i].pad[0] = 0x8d;
185         block[i].pad[1] = 0x76;
186         block[i].pad[2] = 0x00;
187     }
188     VirtualProtect( block, BLOCK_SIZE * sizeof(*block), PAGE_EXECUTE_READ, NULL );
189     prev = InterlockedCompareExchangePointer( (void **)&method_blocks[num], block, NULL );
190     if (prev) /* someone beat us to it */
191     {
192         VirtualFree( block, 0, MEM_RELEASE );
193         block = prev;
194     }
195     return block;
196 }
197
198 static BOOL fill_delegated_stub_table(IUnknownVtbl *vtbl, DWORD num)
199 {
200     const void **entry = (const void **)(vtbl + 1);
201     DWORD i, j;
202
203     vtbl->QueryInterface = delegating_QueryInterface;
204     vtbl->AddRef = delegating_AddRef;
205     vtbl->Release = delegating_Release;
206     for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++)
207     {
208         const vtbl_method_t *block = method_blocks[i];
209         if (!block && !(block = allocate_block( i ))) return FALSE;
210         for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++) *entry++ = &block[j];
211     }
212     return TRUE;
213 }
214
215 #else  /* __i386__ */
216
217 static BOOL fill_delegated_stub_table(IUnknownVtbl *vtbl, DWORD num)
218 {
219     ERR("delegated stubs are not supported on this architecture\n");
220     return FALSE;
221 }
222
223 #endif  /* __i386__ */
224
225 static IUnknownVtbl *get_delegating_vtbl(DWORD num_methods)
226 {
227     IUnknownVtbl *ret;
228
229     if (num_methods < 256) num_methods = 256;  /* avoid frequent reallocations */
230
231     EnterCriticalSection(&delegating_vtbl_section);
232
233     if(!current_vtbl || num_methods > current_vtbl->size)
234     {
235         ref_counted_vtbl *table = HeapAlloc(GetProcessHeap(), 0,
236                                             FIELD_OFFSET(ref_counted_vtbl, vtbl) + num_methods * sizeof(void*));
237         if (!table)
238         {
239             LeaveCriticalSection(&delegating_vtbl_section);
240             return NULL;
241         }
242
243         table->ref = 0;
244         table->size = num_methods;
245         fill_delegated_stub_table(&table->vtbl, num_methods);
246
247         if (current_vtbl && current_vtbl->ref == 0)
248         {
249             TRACE("freeing old table\n");
250             HeapFree(GetProcessHeap(), 0, current_vtbl);
251         }
252         current_vtbl = table;
253     }
254
255     current_vtbl->ref++;
256     ret = &current_vtbl->vtbl;
257     LeaveCriticalSection(&delegating_vtbl_section);
258     return ret;
259 }
260
261 static void release_delegating_vtbl(IUnknownVtbl *vtbl)
262 {
263     ref_counted_vtbl *table = (ref_counted_vtbl*)((DWORD *)vtbl - 1);
264
265     EnterCriticalSection(&delegating_vtbl_section);
266     table->ref--;
267     TRACE("ref now %d\n", table->ref);
268     if(table->ref == 0 && table != current_vtbl)
269     {
270         TRACE("... and we're not current so free'ing\n");
271         HeapFree(GetProcessHeap(), 0, table);
272     }
273     LeaveCriticalSection(&delegating_vtbl_section);
274 }
275
276 HRESULT CStdStubBuffer_Delegating_Construct(REFIID riid,
277                                             LPUNKNOWN pUnkServer,
278                                             PCInterfaceName name,
279                                             CInterfaceStubVtbl *vtbl,
280                                             REFIID delegating_iid,
281                                             LPPSFACTORYBUFFER pPSFactory,
282                                             LPRPCSTUBBUFFER *ppStub)
283 {
284     cstdstubbuffer_delegating_t *This;
285     IUnknown *pvServer;
286     HRESULT r;
287
288     TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name);
289     TRACE("iid=%s delegating to %s\n", debugstr_guid(vtbl->header.piid), debugstr_guid(delegating_iid));
290     TRACE("vtbl=%p\n", &vtbl->Vtbl);
291
292     if (!IsEqualGUID(vtbl->header.piid, riid))
293     {
294         ERR("IID mismatch during stub creation\n");
295         return RPC_E_UNEXPECTED;
296     }
297
298     r = IUnknown_QueryInterface(pUnkServer, riid, (void**)&pvServer);
299     if(FAILED(r)) return r;
300
301     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
302     if (!This)
303     {
304         IUnknown_Release(pvServer);
305         return E_OUTOFMEMORY;
306     }
307
308     This->base_obj = get_delegating_vtbl( vtbl->header.DispatchTableCount );
309     r = create_stub(delegating_iid, (IUnknown*)&This->base_obj, &This->base_stub);
310     if(FAILED(r))
311     {
312         release_delegating_vtbl(This->base_obj);
313         HeapFree(GetProcessHeap(), 0, This);
314         IUnknown_Release(pvServer);
315         return r;
316     }
317
318     This->stub_buffer.lpVtbl = &vtbl->Vtbl;
319     This->stub_buffer.RefCount = 1;
320     This->stub_buffer.pvServerObject = pvServer;
321     This->stub_buffer.pPSFactory = pPSFactory;
322     *ppStub = (LPRPCSTUBBUFFER)&This->stub_buffer;
323
324     IPSFactoryBuffer_AddRef(pPSFactory);
325     return S_OK;
326 }
327
328 HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface,
329                                             REFIID riid,
330                                             LPVOID *obj)
331 {
332   CStdStubBuffer *This = (CStdStubBuffer *)iface;
333   TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj);
334
335   if (IsEqualIID(&IID_IUnknown, riid) ||
336       IsEqualIID(&IID_IRpcStubBuffer, riid))
337   {
338     IUnknown_AddRef(iface);
339     *obj = iface;
340     return S_OK;
341   }
342   *obj = NULL;
343   return E_NOINTERFACE;
344 }
345
346 ULONG WINAPI CStdStubBuffer_AddRef(LPRPCSTUBBUFFER iface)
347 {
348   CStdStubBuffer *This = (CStdStubBuffer *)iface;
349   TRACE("(%p)->AddRef()\n",This);
350   return InterlockedIncrement(&This->RefCount);
351 }
352
353 ULONG WINAPI NdrCStdStubBuffer_Release(LPRPCSTUBBUFFER iface,
354                                       LPPSFACTORYBUFFER pPSF)
355 {
356   CStdStubBuffer *This = (CStdStubBuffer *)iface;
357   ULONG refs;
358
359   TRACE("(%p)->Release()\n",This);
360
361   refs = InterlockedDecrement(&This->RefCount);
362   if (!refs)
363   {
364     /* test_Release shows that native doesn't call Disconnect here.
365        We'll leave it in for the time being. */
366     IRpcStubBuffer_Disconnect(iface);
367
368     IPSFactoryBuffer_Release(pPSF);
369     HeapFree(GetProcessHeap(),0,This);
370   }
371   return refs;
372 }
373
374 ULONG WINAPI NdrCStdStubBuffer2_Release(LPRPCSTUBBUFFER iface,
375                                         LPPSFACTORYBUFFER pPSF)
376 {
377     cstdstubbuffer_delegating_t *This = impl_from_delegating( iface );
378     ULONG refs;
379
380     TRACE("(%p)->Release()\n", This);
381
382     refs = InterlockedDecrement(&This->stub_buffer.RefCount);
383     if (!refs)
384     {
385         /* Just like NdrCStdStubBuffer_Release, we shouldn't call
386            Disconnect here */
387         IRpcStubBuffer_Disconnect((IRpcStubBuffer *)&This->stub_buffer);
388
389         IRpcStubBuffer_Release(This->base_stub);
390         release_delegating_vtbl(This->base_obj);
391
392         IPSFactoryBuffer_Release(pPSF);
393         HeapFree(GetProcessHeap(), 0, This);
394     }
395
396     return refs;
397 }
398
399 HRESULT WINAPI CStdStubBuffer_Connect(LPRPCSTUBBUFFER iface,
400                                      LPUNKNOWN lpUnkServer)
401 {
402     CStdStubBuffer *This = (CStdStubBuffer *)iface;
403     HRESULT r;
404     IUnknown *new = NULL;
405
406     TRACE("(%p)->Connect(%p)\n",This,lpUnkServer);
407
408     r = IUnknown_QueryInterface(lpUnkServer, STUB_HEADER(This).piid, (void**)&new);
409     new = InterlockedExchangePointer((void**)&This->pvServerObject, new);
410     if(new)
411         IUnknown_Release(new);
412     return r;
413 }
414
415 void WINAPI CStdStubBuffer_Disconnect(LPRPCSTUBBUFFER iface)
416 {
417     CStdStubBuffer *This = (CStdStubBuffer *)iface;
418     IUnknown *old;
419     TRACE("(%p)->Disconnect()\n",This);
420
421     old = InterlockedExchangePointer((void**)&This->pvServerObject, NULL);
422
423     if(old)
424         IUnknown_Release(old);
425 }
426
427 HRESULT WINAPI CStdStubBuffer_Invoke(LPRPCSTUBBUFFER iface,
428                                     PRPCOLEMESSAGE pMsg,
429                                     LPRPCCHANNELBUFFER pChannel)
430 {
431   CStdStubBuffer *This = (CStdStubBuffer *)iface;
432   DWORD dwPhase = STUB_UNMARSHAL;
433   HRESULT hr = S_OK;
434
435   TRACE("(%p)->Invoke(%p,%p)\n",This,pMsg,pChannel);
436
437   __TRY
438   {
439     if (STUB_HEADER(This).pDispatchTable)
440       STUB_HEADER(This).pDispatchTable[pMsg->iMethod](iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase);
441     else /* pure interpreted */
442       NdrStubCall2(iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase);
443   }
444   __EXCEPT(stub_filter)
445   {
446     DWORD dwExceptionCode = GetExceptionCode();
447     WARN("a stub call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
448     if (FAILED(dwExceptionCode))
449       hr = dwExceptionCode;
450     else
451       hr = HRESULT_FROM_WIN32(dwExceptionCode);
452   }
453   __ENDTRY
454
455   return hr;
456 }
457
458 LPRPCSTUBBUFFER WINAPI CStdStubBuffer_IsIIDSupported(LPRPCSTUBBUFFER iface,
459                                                     REFIID riid)
460 {
461   CStdStubBuffer *This = (CStdStubBuffer *)iface;
462   TRACE("(%p)->IsIIDSupported(%s)\n",This,debugstr_guid(riid));
463   return IsEqualGUID(STUB_HEADER(This).piid, riid) ? iface : NULL;
464 }
465
466 ULONG WINAPI CStdStubBuffer_CountRefs(LPRPCSTUBBUFFER iface)
467 {
468   CStdStubBuffer *This = (CStdStubBuffer *)iface;
469   TRACE("(%p)->CountRefs()\n",This);
470   return This->RefCount;
471 }
472
473 HRESULT WINAPI CStdStubBuffer_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,
474                                                        LPVOID *ppv)
475 {
476   CStdStubBuffer *This = (CStdStubBuffer *)iface;
477   TRACE("(%p)->DebugServerQueryInterface(%p)\n",This,ppv);
478   return S_OK;
479 }
480
481 void WINAPI CStdStubBuffer_DebugServerRelease(LPRPCSTUBBUFFER iface,
482                                              LPVOID pv)
483 {
484   CStdStubBuffer *This = (CStdStubBuffer *)iface;
485   TRACE("(%p)->DebugServerRelease(%p)\n",This,pv);
486 }
487
488 const IRpcStubBufferVtbl CStdStubBuffer_Vtbl =
489 {
490     CStdStubBuffer_QueryInterface,
491     CStdStubBuffer_AddRef,
492     NULL,
493     CStdStubBuffer_Connect,
494     CStdStubBuffer_Disconnect,
495     CStdStubBuffer_Invoke,
496     CStdStubBuffer_IsIIDSupported,
497     CStdStubBuffer_CountRefs,
498     CStdStubBuffer_DebugServerQueryInterface,
499     CStdStubBuffer_DebugServerRelease
500 };
501
502 static HRESULT WINAPI CStdStubBuffer_Delegating_Connect(LPRPCSTUBBUFFER iface,
503                                                         LPUNKNOWN lpUnkServer)
504 {
505     cstdstubbuffer_delegating_t *This = impl_from_delegating(iface);
506     HRESULT r;
507     TRACE("(%p)->Connect(%p)\n", This, lpUnkServer);
508
509     r = CStdStubBuffer_Connect(iface, lpUnkServer);
510     if(SUCCEEDED(r))
511         r = IRpcStubBuffer_Connect(This->base_stub, (IUnknown*)&This->base_obj);
512
513     return r;
514 }
515
516 static void WINAPI CStdStubBuffer_Delegating_Disconnect(LPRPCSTUBBUFFER iface)
517 {
518     cstdstubbuffer_delegating_t *This = impl_from_delegating(iface);
519     TRACE("(%p)->Disconnect()\n", This);
520
521     IRpcStubBuffer_Disconnect(This->base_stub);
522     CStdStubBuffer_Disconnect(iface);
523 }
524
525 static ULONG WINAPI CStdStubBuffer_Delegating_CountRefs(LPRPCSTUBBUFFER iface)
526 {
527     cstdstubbuffer_delegating_t *This = impl_from_delegating(iface);
528     ULONG ret;
529     TRACE("(%p)->CountRefs()\n", This);
530
531     ret = CStdStubBuffer_CountRefs(iface);
532     ret += IRpcStubBuffer_CountRefs(This->base_stub);
533
534     return ret;
535 }
536
537 const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl =
538 {
539     CStdStubBuffer_QueryInterface,
540     CStdStubBuffer_AddRef,
541     NULL,
542     CStdStubBuffer_Delegating_Connect,
543     CStdStubBuffer_Delegating_Disconnect,
544     CStdStubBuffer_Invoke,
545     CStdStubBuffer_IsIIDSupported,
546     CStdStubBuffer_Delegating_CountRefs,
547     CStdStubBuffer_DebugServerQueryInterface,
548     CStdStubBuffer_DebugServerRelease
549 };
550
551 const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface)
552 {
553   CStdStubBuffer *This = (CStdStubBuffer *)iface;
554   return STUB_HEADER(This).pServerInfo;
555 }
556
557 /************************************************************************
558  *           NdrStubForwardingFunction [RPCRT4.@]
559  */
560 void __RPC_STUB NdrStubForwardingFunction( IRpcStubBuffer *iface, IRpcChannelBuffer *pChannel,
561                                            PRPC_MESSAGE pMsg, DWORD *pdwStubPhase )
562 {
563     /* Note pMsg is passed intact since RPCOLEMESSAGE is basically a RPC_MESSAGE. */
564
565     cstdstubbuffer_delegating_t *This = impl_from_delegating(iface);
566     HRESULT r = IRpcStubBuffer_Invoke(This->base_stub, (RPCOLEMESSAGE*)pMsg, pChannel);
567     if(FAILED(r)) RpcRaiseException(r);
568     return;
569 }
570
571 /***********************************************************************
572  *           NdrStubInitialize [RPCRT4.@]
573  */
574 void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg,
575                              PMIDL_STUB_MESSAGE pStubMsg,
576                              PMIDL_STUB_DESC pStubDescriptor,
577                              LPRPCCHANNELBUFFER pRpcChannelBuffer)
578 {
579   TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer);
580   NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor);
581   pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer;
582   IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer,
583                                &pStubMsg->dwDestContext,
584                                &pStubMsg->pvDestContext);
585 }
586
587 /***********************************************************************
588  *           NdrStubGetBuffer [RPCRT4.@]
589  */
590 void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER iface,
591                             LPRPCCHANNELBUFFER pRpcChannelBuffer,
592                             PMIDL_STUB_MESSAGE pStubMsg)
593 {
594   CStdStubBuffer *This = (CStdStubBuffer *)iface;
595   HRESULT hr;
596
597   TRACE("(%p, %p, %p)\n", This, pRpcChannelBuffer, pStubMsg);
598
599   pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength;
600   hr = IRpcChannelBuffer_GetBuffer(pRpcChannelBuffer,
601     (RPCOLEMESSAGE *)pStubMsg->RpcMsg, STUB_HEADER(This).piid);
602   if (FAILED(hr))
603   {
604     RpcRaiseException(hr);
605     return;
606   }
607
608   pStubMsg->Buffer = pStubMsg->RpcMsg->Buffer;
609 }