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