rpcrt4: Fix a cstub test failure on older versions of Windows.
[wine] / dlls / rpcrt4 / tests / cstub.c
1 /*
2  * Unit test suite for cstubs
3  *
4  * Copyright 2006 Huw Davies
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 <stdarg.h>
22
23 #define PROXY_DELEGATION
24 #define COBJMACROS
25
26 #include "wine/test.h"
27 #include <windef.h>
28 #include <winbase.h>
29 #include <winnt.h>
30 #include <winerror.h>
31
32
33 #include "initguid.h"
34 #include "rpc.h"
35 #include "rpcdce.h"
36 #include "rpcproxy.h"
37
38 static CStdPSFactoryBuffer PSFactoryBuffer;
39
40 CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer)
41 CSTDSTUBBUFFER2RELEASE(&PSFactoryBuffer)
42
43 static GUID IID_if1 = {0x12345678, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
44 static GUID IID_if2 = {0x12345679, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
45 static GUID IID_if3 = {0x1234567a, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
46 static GUID IID_if4 = {0x1234567b, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
47
48 static int my_alloc_called;
49 static int my_free_called;
50
51 static void * CALLBACK my_alloc(size_t size)
52 {
53     my_alloc_called++;
54     return NdrOleAllocate(size);
55 }
56
57 static void CALLBACK my_free(void *ptr)
58 {
59     my_free_called++;
60     NdrOleFree(ptr);
61 }
62
63 typedef struct _MIDL_PROC_FORMAT_STRING
64 {
65     short          Pad;
66     unsigned char  Format[ 2 ];
67 } MIDL_PROC_FORMAT_STRING;
68
69 typedef struct _MIDL_TYPE_FORMAT_STRING
70 {
71     short          Pad;
72     unsigned char  Format[ 2 ];
73 } MIDL_TYPE_FORMAT_STRING;
74
75
76 static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =
77 {
78     0,
79     {
80         0, 0
81     }
82 };
83
84 static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =
85 {
86     0,
87     {
88         0, 0
89     }
90 };
91
92 static const MIDL_STUB_DESC Object_StubDesc =
93     {
94     NULL,
95     my_alloc,
96     my_free,
97     { 0 },
98     0,
99     0,
100     0,
101     0,
102     __MIDL_TypeFormatString.Format,
103     1, /* -error bounds_check flag */
104     0x20000, /* Ndr library version */
105     0,
106     0x50100a4, /* MIDL Version 5.1.164 */
107     0,
108     NULL,
109     0,  /* notify & notify_flag routine table */
110     1,  /* Flags */
111     0,  /* Reserved3 */
112     0,  /* Reserved4 */
113     0   /* Reserved5 */
114     };
115
116 static HRESULT WINAPI if1_fn1_Proxy(void *This)
117 {
118     return S_OK;
119 }
120
121 static void __RPC_STUB if1_fn1_Stub(
122     IRpcStubBuffer *This,
123     IRpcChannelBuffer *_pRpcChannelBuffer,
124     PRPC_MESSAGE _pRpcMessage,
125     DWORD *_pdwStubPhase)
126 {
127     trace("fn1 stub\n");
128 }
129
130 static HRESULT WINAPI if1_fn2_Proxy(void *This)
131 {
132     return S_OK;
133 }
134
135 static void __RPC_STUB if1_fn2_Stub(
136     IRpcStubBuffer *This,
137     IRpcChannelBuffer *_pRpcChannelBuffer,
138     PRPC_MESSAGE _pRpcMessage,
139     DWORD *_pdwStubPhase)
140 {
141     trace("fn2 stub\n");
142 }
143
144 static CINTERFACE_PROXY_VTABLE(5) if1_proxy_vtbl =
145 {
146     { &IID_if1 },
147     {   IUnknown_QueryInterface_Proxy,
148         IUnknown_AddRef_Proxy,
149         IUnknown_Release_Proxy ,
150         if1_fn1_Proxy,
151         if1_fn2_Proxy
152     }
153 };
154
155
156 static const unsigned short if1_FormatStringOffsetTable[] =
157     {
158     0,
159     0
160     };
161
162 static const MIDL_SERVER_INFO if1_server_info =
163     {
164     &Object_StubDesc,
165     0,
166     __MIDL_ProcFormatString.Format,
167     &if1_FormatStringOffsetTable[-3],
168     0,
169     0,
170     0,
171     0};
172
173
174 static const PRPC_STUB_FUNCTION if1_table[] =
175 {
176     if1_fn1_Stub,
177     if1_fn2_Stub
178 };
179
180 static CInterfaceStubVtbl if1_stub_vtbl =
181 {
182     {
183         &IID_if1,
184         &if1_server_info,
185         5,
186         &if1_table[-3]
187     },
188     { CStdStubBuffer_METHODS }
189 };
190
191 static CINTERFACE_PROXY_VTABLE(13) if2_proxy_vtbl =
192 {
193     { &IID_if2 },
194     {   IUnknown_QueryInterface_Proxy,
195         IUnknown_AddRef_Proxy,
196         IUnknown_Release_Proxy ,
197         0,
198         0,
199         0,
200         0,
201         0,
202         0,
203         0,
204         0,
205         0,
206         0
207     }
208 };
209
210 static const unsigned short if2_FormatStringOffsetTable[] =
211     {
212     (unsigned short) -1,
213     (unsigned short) -1,
214     (unsigned short) -1,
215     (unsigned short) -1,
216     (unsigned short) -1,
217     (unsigned short) -1,
218     (unsigned short) -1,
219     (unsigned short) -1,
220     (unsigned short) -1,
221     (unsigned short) -1,
222     0
223     };
224
225 static const MIDL_SERVER_INFO if2_server_info =
226     {
227     &Object_StubDesc,
228     0,
229     __MIDL_ProcFormatString.Format,
230     &if2_FormatStringOffsetTable[-3],
231     0,
232     0,
233     0,
234     0};
235
236
237 static const PRPC_STUB_FUNCTION if2_table[] =
238 {
239     STUB_FORWARDING_FUNCTION,
240     STUB_FORWARDING_FUNCTION,
241     STUB_FORWARDING_FUNCTION,
242     STUB_FORWARDING_FUNCTION,
243     STUB_FORWARDING_FUNCTION,
244     STUB_FORWARDING_FUNCTION,
245     STUB_FORWARDING_FUNCTION,
246     STUB_FORWARDING_FUNCTION,
247     STUB_FORWARDING_FUNCTION,
248     STUB_FORWARDING_FUNCTION
249 };
250
251 static CInterfaceStubVtbl if2_stub_vtbl =
252 {
253     {
254         &IID_if2,
255         &if2_server_info,
256         13,
257         &if2_table[-3]
258     },
259     { CStdStubBuffer_DELEGATING_METHODS }
260 };
261
262 static CINTERFACE_PROXY_VTABLE(4) if3_proxy_vtbl =
263 {
264     { &IID_if3 },
265     {   IUnknown_QueryInterface_Proxy,
266         IUnknown_AddRef_Proxy,
267         IUnknown_Release_Proxy ,
268         if1_fn1_Proxy
269     }
270 };
271
272
273 static const unsigned short if3_FormatStringOffsetTable[] =
274     {
275     0,
276     0
277     };
278
279 static const MIDL_SERVER_INFO if3_server_info =
280     {
281     &Object_StubDesc,
282     0,
283     __MIDL_ProcFormatString.Format,
284     &if3_FormatStringOffsetTable[-3],
285     0,
286     0,
287     0,
288     0};
289
290
291 static const PRPC_STUB_FUNCTION if3_table[] =
292 {
293     if1_fn1_Stub
294 };
295
296 static CInterfaceStubVtbl if3_stub_vtbl =
297 {
298     {
299         &IID_if3,
300         &if3_server_info,
301         4,
302         &if1_table[-3]
303     },
304     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
305 };
306
307 static CINTERFACE_PROXY_VTABLE(7) if4_proxy_vtbl =
308 {
309     { &IID_if4 },
310     {   IUnknown_QueryInterface_Proxy,
311         IUnknown_AddRef_Proxy,
312         IUnknown_Release_Proxy ,
313         0,
314         0,
315         0,
316         0
317     }
318 };
319
320 static const unsigned short if4_FormatStringOffsetTable[] =
321     {
322     (unsigned short) -1,
323     (unsigned short) -1,
324     (unsigned short) -1,
325     (unsigned short) -1,
326     0
327     };
328
329 static const MIDL_SERVER_INFO if4_server_info =
330     {
331     &Object_StubDesc,
332     0,
333     __MIDL_ProcFormatString.Format,
334     &if4_FormatStringOffsetTable[-3],
335     0,
336     0,
337     0,
338     0};
339
340
341 static const PRPC_STUB_FUNCTION if4_table[] =
342 {
343     STUB_FORWARDING_FUNCTION,
344     STUB_FORWARDING_FUNCTION,
345     STUB_FORWARDING_FUNCTION,
346     STUB_FORWARDING_FUNCTION,
347 };
348
349 static CInterfaceStubVtbl if4_stub_vtbl =
350 {
351     {
352         &IID_if4,
353         &if4_server_info,
354         7,
355         &if2_table[-3]
356     },
357     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
358 };
359
360 static const CInterfaceProxyVtbl *cstub_ProxyVtblList[] =
361 {
362     (const CInterfaceProxyVtbl *) &if1_proxy_vtbl,
363     (const CInterfaceProxyVtbl *) &if2_proxy_vtbl,
364     (const CInterfaceProxyVtbl *) &if3_proxy_vtbl,
365     (const CInterfaceProxyVtbl *) &if4_proxy_vtbl,
366     NULL
367 };
368
369 static const CInterfaceStubVtbl *cstub_StubVtblList[] =
370 {
371     (const CInterfaceStubVtbl *) &if1_stub_vtbl,
372     (const CInterfaceStubVtbl *) &if2_stub_vtbl,
373     (const CInterfaceStubVtbl *) &if3_stub_vtbl,
374     (const CInterfaceStubVtbl *) &if4_stub_vtbl,
375     NULL
376 };
377
378 static PCInterfaceName const if_name_list[] =
379 {
380     "if1",
381     "if2",
382     "if3",
383     "if4",
384     NULL
385 };
386
387 static const IID *base_iid_list[] =
388 {
389     NULL,
390     &IID_ITypeLib,
391     NULL,
392     &IID_IDispatch,
393     NULL
394 };
395
396 #define cstub_CHECK_IID(n)     IID_GENERIC_CHECK_IID( cstub, pIID, n)
397
398 static int __stdcall iid_lookup( const IID * pIID, int * pIndex )
399 {
400     IID_BS_LOOKUP_SETUP
401
402     IID_BS_LOOKUP_INITIAL_TEST( cstub, 4, 4 )
403     IID_BS_LOOKUP_NEXT_TEST( cstub, 2 )
404     IID_BS_LOOKUP_NEXT_TEST( cstub, 1 )
405     IID_BS_LOOKUP_RETURN_RESULT( cstub, 4, *pIndex )
406
407 }
408
409
410 static const ExtendedProxyFileInfo my_proxy_file_info =
411 {
412     (const PCInterfaceProxyVtblList *) &cstub_ProxyVtblList,
413     (const PCInterfaceStubVtblList *) &cstub_StubVtblList,
414     (const PCInterfaceName *) &if_name_list,
415     (const IID **) &base_iid_list,
416     &iid_lookup,
417     4,
418     1,
419     NULL,
420     0,
421     0,
422     0
423 };
424
425 static const ProxyFileInfo *proxy_file_list[] = {
426     &my_proxy_file_info,
427     NULL
428 };
429
430
431 static IPSFactoryBuffer *test_NdrDllGetClassObject(void)
432 {
433     IPSFactoryBuffer *ppsf = NULL;
434     const CLSID PSDispatch = {0x20420, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
435     const CLSID CLSID_Unknown = {0x45678, 0x1234, 0x6666, {0xff, 0x67, 0x45, 0x98, 0x76, 0x12, 0x34, 0x56}};
436     HRESULT r;
437     HMODULE hmod = GetModuleHandleA("rpcrt4.dll");
438     void *CStd_QueryInterface = GetProcAddress(hmod, "CStdStubBuffer_QueryInterface");
439     void *CStd_AddRef = GetProcAddress(hmod, "CStdStubBuffer_AddRef");
440     void *CStd_Release = GetProcAddress(hmod, "NdrCStdStubBuffer_Release");
441     void *CStd_Connect = GetProcAddress(hmod, "CStdStubBuffer_Connect");
442     void *CStd_Disconnect = GetProcAddress(hmod, "CStdStubBuffer_Disconnect");
443     void *CStd_Invoke = GetProcAddress(hmod, "CStdStubBuffer_Invoke");
444     void *CStd_IsIIDSupported = GetProcAddress(hmod, "CStdStubBuffer_IsIIDSupported");
445     void *CStd_CountRefs = GetProcAddress(hmod, "CStdStubBuffer_CountRefs");
446     void *CStd_DebugServerQueryInterface = GetProcAddress(hmod, "CStdStubBuffer_DebugServerQueryInterface");
447     void *CStd_DebugServerRelease = GetProcAddress(hmod, "CStdStubBuffer_DebugServerRelease");
448
449     r = NdrDllGetClassObject(&PSDispatch, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
450                              &CLSID_Unknown, &PSFactoryBuffer);
451     ok(r == CLASS_E_CLASSNOTAVAILABLE, "NdrDllGetClassObject with unknown clsid should have returned CLASS_E_CLASSNOTAVAILABLE instead of 0x%x\n", r);
452     ok(ppsf == NULL, "NdrDllGetClassObject should have set ppsf to NULL on failure\n");
453
454     r = NdrDllGetClassObject(&PSDispatch, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
455                          &PSDispatch, &PSFactoryBuffer);
456
457     ok(r == S_OK, "ret %08x\n", r);
458     ok(ppsf != NULL, "ppsf == NULL\n");
459
460     ok(PSFactoryBuffer.pProxyFileList == proxy_file_list, "pfl not the same\n");
461     ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList == (PCInterfaceStubVtblList *) &cstub_StubVtblList, "stub vtbllist not the same\n");
462
463     /* if1 is non-delegating, if2 is delegating, if3 is non-delegating
464        but I've zero'ed the vtbl entries, similarly if4 is delegating
465        with zero'ed vtbl entries */
466
467 #define VTBL_TEST_NOT_CHANGE_TO(name, i)                                  \
468     ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name != CStd_##name, #name "vtbl %d updated %p %p\n", \
469        i, PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name, CStd_##name );
470 #define VTBL_TEST_CHANGE_TO(name, i)                                  \
471     ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name == CStd_##name, #name "vtbl %d not updated %p %p\n", \
472        i, PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name, CStd_##name );
473 #define VTBL_TEST_ZERO(name, i)                                  \
474     ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name == NULL, #name "vtbl %d not null %p\n", \
475        i, PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name );
476     VTBL_TEST_NOT_CHANGE_TO(QueryInterface, 0);
477     VTBL_TEST_NOT_CHANGE_TO(AddRef, 0);
478     VTBL_TEST_NOT_CHANGE_TO(Release, 0);
479     VTBL_TEST_NOT_CHANGE_TO(Connect, 0);
480     VTBL_TEST_NOT_CHANGE_TO(Disconnect, 0);
481     VTBL_TEST_NOT_CHANGE_TO(Invoke, 0);
482     VTBL_TEST_NOT_CHANGE_TO(IsIIDSupported, 0);
483     VTBL_TEST_NOT_CHANGE_TO(CountRefs, 0);
484     VTBL_TEST_NOT_CHANGE_TO(DebugServerQueryInterface, 0);
485     VTBL_TEST_NOT_CHANGE_TO(DebugServerRelease, 0);
486
487     VTBL_TEST_CHANGE_TO(QueryInterface, 1);
488     VTBL_TEST_CHANGE_TO(AddRef, 1);
489     VTBL_TEST_NOT_CHANGE_TO(Release, 1);
490     VTBL_TEST_NOT_CHANGE_TO(Connect, 1);
491     VTBL_TEST_NOT_CHANGE_TO(Disconnect, 1);
492     VTBL_TEST_CHANGE_TO(Invoke, 1);
493     VTBL_TEST_CHANGE_TO(IsIIDSupported, 1);
494     VTBL_TEST_NOT_CHANGE_TO(CountRefs, 1);
495     VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 1);
496     VTBL_TEST_CHANGE_TO(DebugServerRelease, 1);
497
498     VTBL_TEST_CHANGE_TO(QueryInterface, 2);
499     VTBL_TEST_CHANGE_TO(AddRef, 2);
500     VTBL_TEST_ZERO(Release, 2);
501     VTBL_TEST_CHANGE_TO(Connect, 2);
502     VTBL_TEST_CHANGE_TO(Disconnect, 2);
503     VTBL_TEST_CHANGE_TO(Invoke, 2);
504     VTBL_TEST_CHANGE_TO(IsIIDSupported, 2);
505     VTBL_TEST_CHANGE_TO(CountRefs, 2);
506     VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 2);
507     VTBL_TEST_CHANGE_TO(DebugServerRelease, 2);
508
509     VTBL_TEST_CHANGE_TO(QueryInterface, 3);
510     VTBL_TEST_CHANGE_TO(AddRef, 3);
511     VTBL_TEST_ZERO(Release, 3);
512     VTBL_TEST_NOT_CHANGE_TO(Connect, 3);
513     VTBL_TEST_NOT_CHANGE_TO(Disconnect, 3);
514     VTBL_TEST_CHANGE_TO(Invoke, 3);
515     VTBL_TEST_CHANGE_TO(IsIIDSupported, 3);
516     VTBL_TEST_NOT_CHANGE_TO(CountRefs, 3);
517     VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 3);
518     VTBL_TEST_CHANGE_TO(DebugServerRelease, 3);
519
520
521
522 #undef VTBL_TEST_NOT_CHANGE_TO
523 #undef VTBL_TEST_CHANGE_TO
524 #undef VTBL_TEST_ZERO
525
526     ok(PSFactoryBuffer.RefCount == 1, "ref count %d\n", PSFactoryBuffer.RefCount);
527     IPSFactoryBuffer_Release(ppsf);
528
529     r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
530                              NULL, &PSFactoryBuffer);
531     ok(r == S_OK, "ret %08x\n", r);
532     ok(ppsf != NULL, "ppsf == NULL\n");
533
534     return ppsf;
535 }
536
537 static int base_buffer_invoke_called;
538 static HRESULT WINAPI base_buffer_Invoke(IRpcStubBuffer *This, RPCOLEMESSAGE *msg, IRpcChannelBuffer *channel)
539 {
540     base_buffer_invoke_called++;
541     ok(msg == (RPCOLEMESSAGE*)0xcafebabe, "msg ptr changed\n");
542     ok(channel == (IRpcChannelBuffer*)0xdeadbeef, "channel ptr changed\n");
543     return S_OK; /* returning any failure here results in an exception */
544 }
545
546 static IRpcStubBufferVtbl base_buffer_vtbl = {
547     (void*)0xcafebab0,
548     (void*)0xcafebab1,
549     (void*)0xcafebab2,
550     (void*)0xcafebab3,
551     (void*)0xcafebab4,
552     base_buffer_Invoke,
553     (void*)0xcafebab6,
554     (void*)0xcafebab7,
555     (void*)0xcafebab8,
556     (void*)0xcafebab9
557 };
558
559 static void test_NdrStubForwardingFunction(void)
560 {
561     void *This[5];
562     void *real_this;
563     IRpcChannelBuffer *channel = (IRpcChannelBuffer*)0xdeadbeef;
564     RPC_MESSAGE *msg = (RPC_MESSAGE*)0xcafebabe;
565     DWORD *phase = (DWORD*)0x12345678;
566     IRpcStubBufferVtbl *base_buffer_vtbl_ptr = &base_buffer_vtbl;
567     IRpcStubBuffer *base_stub_buffer = (IRpcStubBuffer*)&base_buffer_vtbl_ptr;
568
569     memset(This, 0xcc, sizeof(This));
570     This[0] = base_stub_buffer;
571     real_this = &This[1];
572
573     NdrStubForwardingFunction( real_this, channel, msg, phase );
574     ok(base_buffer_invoke_called == 1, "base_buffer_invoke called %d times\n", base_buffer_invoke_called);
575
576 }
577
578 static IRpcStubBuffer *create_stub(IPSFactoryBuffer *ppsf, REFIID iid, IUnknown *obj, HRESULT expected_result)
579 {
580     IRpcStubBuffer *pstub = NULL;
581     HRESULT r;
582
583     r = IPSFactoryBuffer_CreateStub(ppsf, iid, obj, &pstub);
584     ok(r == expected_result, "CreateStub returned %08x expected %08x\n", r, expected_result);
585     return pstub;
586 }
587
588 static HRESULT WINAPI create_stub_test_QI(IUnknown *This, REFIID iid, void **ppv)
589 {
590     ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
591     *ppv = (void*)0xdeadbeef;
592     return S_OK;
593 }
594
595 static IUnknownVtbl create_stub_test_vtbl =
596 {
597     create_stub_test_QI,
598     NULL,
599     NULL
600 };
601
602 static HRESULT WINAPI create_stub_test_fail_QI(IUnknown *This, REFIID iid, void **ppv)
603 {
604     ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
605     *ppv = NULL;
606     return E_NOINTERFACE;
607 }
608
609 static IUnknownVtbl create_stub_test_fail_vtbl =
610 {
611     create_stub_test_fail_QI,
612     NULL,
613     NULL
614 };
615
616 static void test_CreateStub(IPSFactoryBuffer *ppsf)
617 {
618     IUnknownVtbl *vtbl = &create_stub_test_vtbl;
619     IUnknown *obj = (IUnknown*)&vtbl;
620     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
621     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
622     const CInterfaceStubHeader *header = ((const CInterfaceStubHeader *)cstd_stub->lpVtbl) - 1;
623
624     ok(IsEqualIID(header->piid, &IID_if1), "header iid differs\n");
625     ok(cstd_stub->RefCount == 1, "ref count %d\n", cstd_stub->RefCount);
626     /* 0xdeadbeef returned from create_stub_test_QI */
627     ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
628     ok(cstd_stub->pPSFactory == ppsf ||
629        broken(cstd_stub->pPSFactory == (void *)0x00001000) /* Win9x & NT4 */,
630        "pPSFactory was %p instead of %p\n", cstd_stub->pPSFactory, ppsf);
631
632     vtbl = &create_stub_test_fail_vtbl;
633     pstub = create_stub(ppsf, &IID_if1, obj, E_NOINTERFACE);
634
635 }
636
637 static HRESULT WINAPI connect_test_orig_QI(IUnknown *This, REFIID iid, void **ppv)
638 {
639     ok(IsEqualIID(iid, &IID_if1) ||
640        IsEqualIID(iid, &IID_if2), "incorrect iid\n");
641     *ppv = (void*)This;
642     return S_OK;
643 }
644
645 static int connect_test_orig_release_called;
646 static ULONG WINAPI connect_test_orig_release(IUnknown *This)
647 {
648     connect_test_orig_release_called++;
649     return 0;
650 }
651
652 static IUnknownVtbl connect_test_orig_vtbl =
653 {
654     connect_test_orig_QI,
655     NULL,
656     connect_test_orig_release
657 };
658
659 static HRESULT WINAPI connect_test_new_QI(IUnknown *This, REFIID iid, void **ppv)
660 {
661     ok(IsEqualIID(iid, &IID_if1) ||
662        IsEqualIID(iid, &IID_if2), "incorrect iid\n");
663     *ppv = (void*)0xcafebabe;
664     return S_OK;
665 }
666
667 static IUnknownVtbl connect_test_new_vtbl =
668 {
669     connect_test_new_QI,
670     NULL,
671     NULL
672 };
673
674 static HRESULT WINAPI connect_test_new_fail_QI(IUnknown *This, REFIID iid, void **ppv)
675 {
676     ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
677     *ppv = (void*)0xdeadbeef;
678     return E_NOINTERFACE;
679 }
680
681 static IUnknownVtbl connect_test_new_fail_vtbl =
682 {
683     connect_test_new_fail_QI,
684     NULL,
685     NULL
686 };
687
688 static int connect_test_base_Connect_called;
689 static HRESULT WINAPI connect_test_base_Connect(IRpcStubBuffer *pstub, IUnknown *obj)
690 {
691     connect_test_base_Connect_called++;
692     ok(*(void**)obj == (void*)0xbeefcafe, "unexpected obj %p\n", obj);
693     return S_OK;
694 }
695
696 static IRpcStubBufferVtbl connect_test_base_stub_buffer_vtbl =
697 {
698     (void*)0xcafebab0,
699     (void*)0xcafebab1,
700     (void*)0xcafebab2,
701     connect_test_base_Connect,
702     (void*)0xcafebab4,
703     (void*)0xcafebab5,
704     (void*)0xcafebab6,
705     (void*)0xcafebab7,
706     (void*)0xcafebab8,
707     (void*)0xcafebab9
708 };
709
710 static void test_Connect(IPSFactoryBuffer *ppsf)
711 {
712     IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
713     IUnknownVtbl *new_vtbl = &connect_test_new_vtbl;
714     IUnknownVtbl *new_fail_vtbl = &connect_test_new_fail_vtbl;
715     IUnknown *obj = (IUnknown*)&orig_vtbl;
716     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK); 
717     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
718     IRpcStubBufferVtbl *base_stub_buf_vtbl = &connect_test_base_stub_buffer_vtbl;
719     HRESULT r;
720
721     obj = (IUnknown*)&new_vtbl;
722     r = IRpcStubBuffer_Connect(pstub, obj);
723     ok(r == S_OK, "r %08x\n", r);
724     ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
725     ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
726
727     cstd_stub->pvServerObject = (IUnknown*)&orig_vtbl;
728     obj = (IUnknown*)&new_fail_vtbl;
729     r = IRpcStubBuffer_Connect(pstub, obj);
730     ok(r == E_NOINTERFACE, "r %08x\n", r);
731     ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
732     ok(connect_test_orig_release_called == 2, "release called %d\n", connect_test_orig_release_called);    
733
734     /* Now use a delegated stub.
735
736        We know from the NdrStubForwardFunction test that
737        (void**)pstub-1 is the base interface stub buffer.  This shows
738        that (void**)pstub-2 contains the address of a vtable that gets
739        passed to the base interface's Connect method.  Note that
740        (void**)pstub-2 itself gets passed to Connect and not
741        *((void**)pstub-2), so it should contain the vtable ptr and not
742        an interface ptr. */
743
744     obj = (IUnknown*)&orig_vtbl;
745     pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
746     *((void**)pstub-1) = &base_stub_buf_vtbl;
747     *((void**)pstub-2) = (void*)0xbeefcafe;
748
749     obj = (IUnknown*)&new_vtbl;
750     r = IRpcStubBuffer_Connect(pstub, obj);
751     ok(connect_test_base_Connect_called == 1, "connect_test_bsae_Connect called %d times\n",
752        connect_test_base_Connect_called);
753     ok(connect_test_orig_release_called == 3, "release called %d\n", connect_test_orig_release_called);
754     cstd_stub = (CStdStubBuffer*)pstub;
755     ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
756 }
757
758 static void test_Disconnect(IPSFactoryBuffer *ppsf)
759 {
760     IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
761     IUnknown *obj = (IUnknown*)&orig_vtbl;
762     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
763     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
764
765     connect_test_orig_release_called = 0;
766     IRpcStubBuffer_Disconnect(pstub);
767     ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
768     ok(cstd_stub->pvServerObject == NULL, "pvServerObject %p\n", cstd_stub->pvServerObject);
769 }
770
771
772 static int release_test_psfacbuf_release_called;
773 static ULONG WINAPI release_test_pretend_psfacbuf_release(IUnknown *pUnk)
774 {
775     release_test_psfacbuf_release_called++;
776     return 1;
777 }
778
779 static IUnknownVtbl release_test_pretend_psfacbuf_vtbl =
780 {
781     NULL,
782     NULL,
783     release_test_pretend_psfacbuf_release
784 };
785
786 static void test_Release(IPSFactoryBuffer *ppsf)
787 {
788     LONG facbuf_refs;
789     IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
790     IUnknown *obj = (IUnknown*)&orig_vtbl;
791     IUnknownVtbl *pretend_psfacbuf_vtbl = &release_test_pretend_psfacbuf_vtbl;
792     IUnknown *pretend_psfacbuf = (IUnknown *)&pretend_psfacbuf_vtbl;
793     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
794     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
795
796     facbuf_refs = PSFactoryBuffer.RefCount;
797
798     /* This shows that NdrCStdStubBuffer_Release doesn't call Disconnect */
799     ok(cstd_stub->RefCount == 1, "ref count %d\n", cstd_stub->RefCount);
800     connect_test_orig_release_called = 0;
801     IRpcStubBuffer_Release(pstub);
802 todo_wine {
803     ok(connect_test_orig_release_called == 0, "release called %d\n", connect_test_orig_release_called);
804 }
805     ok(PSFactoryBuffer.RefCount == facbuf_refs - 1, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
806
807     /* This shows that NdrCStdStubBuffer_Release calls Release on its 2nd arg, rather than on This->pPSFactory
808        (which are usually the same and indeed it's odd that _Release requires this 2nd arg). */
809     pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
810     ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
811     NdrCStdStubBuffer_Release(pstub, (IPSFactoryBuffer*)pretend_psfacbuf);
812     ok(release_test_psfacbuf_release_called == 1, "pretend_psfacbuf_release called %d\n", release_test_psfacbuf_release_called);
813     ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
814 }
815
816 static HRESULT WINAPI delegating_invoke_test_QI(ITypeLib *pUnk, REFIID iid, void** ppv)
817 {
818
819     *ppv = pUnk;
820     return S_OK;
821 }
822
823 static ULONG WINAPI delegating_invoke_test_addref(ITypeLib *pUnk)
824 {
825     return 1;
826 }
827
828 static ULONG WINAPI delegating_invoke_test_release(ITypeLib *pUnk)
829 {
830     return 1;
831 }
832
833 static UINT WINAPI delegating_invoke_test_get_type_info_count(ITypeLib *pUnk)
834 {
835     return 0xabcdef;
836 }
837
838 static ITypeLibVtbl delegating_invoke_test_obj_vtbl =
839 {
840     delegating_invoke_test_QI,
841     delegating_invoke_test_addref,
842     delegating_invoke_test_release,
843     delegating_invoke_test_get_type_info_count,
844     NULL,
845     NULL,
846     NULL,
847     NULL,
848     NULL,
849     NULL,
850     NULL,
851     NULL,
852     NULL
853 };
854
855 static HRESULT WINAPI delegating_invoke_chan_query_interface(IRpcChannelBuffer *pchan,
856                                                              REFIID iid,
857                                                              void **ppv)
858 {
859     ok(0, "call to QueryInterface not expected\n");
860     return E_NOINTERFACE;
861 }
862
863 static ULONG WINAPI delegating_invoke_chan_add_ref(IRpcChannelBuffer *pchan)
864 {
865     return 2;
866 }
867
868 static ULONG WINAPI delegating_invoke_chan_release(IRpcChannelBuffer *pchan)
869 {
870     return 1;
871 }
872
873 static HRESULT WINAPI delegating_invoke_chan_get_buffer(IRpcChannelBuffer *pchan,
874                                                         RPCOLEMESSAGE *msg,
875                                                         REFIID iid)
876 {
877     msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->cbBuffer);
878     return S_OK;
879 }
880
881 static HRESULT WINAPI delegating_invoke_chan_send_receive(IRpcChannelBuffer *pchan,
882                                                           RPCOLEMESSAGE *pMessage,
883                                                           ULONG *pStatus)
884 {
885     ok(0, "call to SendReceive not expected\n");
886     return E_NOTIMPL;
887 }
888
889 static HRESULT WINAPI delegating_invoke_chan_free_buffer(IRpcChannelBuffer *pchan,
890                                                          RPCOLEMESSAGE *pMessage)
891 {
892     ok(0, "call to FreeBuffer not expected\n");
893     return E_NOTIMPL;
894 }
895
896 static HRESULT WINAPI delegating_invoke_chan_get_dest_ctx(IRpcChannelBuffer *pchan,
897                                                           DWORD *pdwDestContext,
898                                                           void **ppvDestContext)
899 {
900     *pdwDestContext = MSHCTX_LOCAL;
901     *ppvDestContext = NULL;
902     return S_OK;
903 }
904
905 static HRESULT WINAPI delegating_invoke_chan_is_connected(IRpcChannelBuffer *pchan)
906 {
907     ok(0, "call to IsConnected not expected\n");
908     return E_NOTIMPL;
909 }
910
911 static IRpcChannelBufferVtbl delegating_invoke_test_rpc_chan_vtbl =
912 {
913     delegating_invoke_chan_query_interface,
914     delegating_invoke_chan_add_ref,
915     delegating_invoke_chan_release,
916     delegating_invoke_chan_get_buffer,
917     delegating_invoke_chan_send_receive,
918     delegating_invoke_chan_free_buffer,
919     delegating_invoke_chan_get_dest_ctx,
920     delegating_invoke_chan_is_connected
921 };
922
923 static void test_delegating_Invoke(IPSFactoryBuffer *ppsf)
924 {
925     ITypeLibVtbl *obj_vtbl = &delegating_invoke_test_obj_vtbl;
926     IUnknown *obj = (IUnknown*)&obj_vtbl;
927     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
928     IRpcChannelBufferVtbl *pchan_vtbl = &delegating_invoke_test_rpc_chan_vtbl;
929     IRpcChannelBuffer *pchan = (IRpcChannelBuffer *)&pchan_vtbl;
930     HRESULT r = E_FAIL;
931     RPCOLEMESSAGE msg;
932
933     memset(&msg, 0, sizeof(msg));
934     msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
935     msg.iMethod = 3;
936     r = IRpcStubBuffer_Invoke(pstub, &msg, pchan);
937     ok(r == S_OK, "ret %08x\n", r);
938     if(r == S_OK)
939     {
940         ok(*(DWORD*)msg.Buffer == 0xabcdef, "buf[0] %08x\n", *(DWORD*)msg.Buffer);
941         ok(*((DWORD*)msg.Buffer + 1) == S_OK, "buf[1] %08x\n", *((DWORD*)msg.Buffer + 1));
942     }
943     /* free the buffer allocated by delegating_invoke_chan_get_buffer */
944     HeapFree(GetProcessHeap(), 0, msg.Buffer);
945     IRpcStubBuffer_Release(pstub);
946 }
947
948 START_TEST( cstub )
949 {
950     IPSFactoryBuffer *ppsf;
951
952     OleInitialize(NULL);
953
954     ppsf = test_NdrDllGetClassObject();
955     test_NdrStubForwardingFunction();
956     test_CreateStub(ppsf);
957     test_Connect(ppsf);
958     test_Disconnect(ppsf);
959     test_Release(ppsf);
960     test_delegating_Invoke(ppsf);
961
962     OleUninitialize();
963 }