rpcrt4/tests: Fix the spelling of a couple of comments.
[wine.git] / dlls / rpcrt4 / tests / cstub.c
blob794d85744ef83385b87676bc21bb7268dca7833f
1 /*
2 * Unit test suite for cstubs
4 * Copyright 2006 Huw Davies
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.
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.
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
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
26 #include <windef.h>
27 #include <winbase.h>
28 #include <winnt.h>
29 #include <winerror.h>
31 #include "initguid.h"
32 #include <ole2.h>
33 #include "rpc.h"
34 #include "rpcdce.h"
35 #include "rpcproxy.h"
37 #include "wine/heap.h"
38 #include "wine/test.h"
40 #include "cstub.h"
42 static CStdPSFactoryBuffer PSFactoryBuffer;
44 static ULONG WINAPI test_CStdStubBuffer_Release(IRpcStubBuffer *This)
46 return NdrCStdStubBuffer_Release(This, (IPSFactoryBuffer *)&PSFactoryBuffer);
49 static ULONG WINAPI test_CStdStubBuffer2_Release(IRpcStubBuffer *This)
51 return NdrCStdStubBuffer2_Release(This, (IPSFactoryBuffer *)&PSFactoryBuffer);
54 static GUID IID_if1 = {0x12345678, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
55 static GUID IID_if2 = {0x12345679, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
56 static GUID IID_if3 = {0x1234567a, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
57 static GUID IID_if4 = {0x1234567b, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
58 static CLSID CLSID_psfact = {0x1234567c, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
60 static int my_alloc_called;
61 static int my_free_called;
63 static void * CALLBACK my_alloc(SIZE_T size)
65 my_alloc_called++;
66 return NdrOleAllocate(size);
69 static void CALLBACK my_free(void *ptr)
71 my_free_called++;
72 NdrOleFree(ptr);
75 typedef struct _MIDL_PROC_FORMAT_STRING
77 short Pad;
78 unsigned char Format[ 2 ];
79 } MIDL_PROC_FORMAT_STRING;
81 typedef struct _MIDL_TYPE_FORMAT_STRING
83 short Pad;
84 unsigned char Format[ 2 ];
85 } MIDL_TYPE_FORMAT_STRING;
88 static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =
92 0, 0
96 static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =
100 0, 0
104 static const MIDL_STUB_DESC Object_StubDesc =
106 NULL,
107 my_alloc,
108 my_free,
109 { 0 },
114 __MIDL_TypeFormatString.Format,
115 1, /* -error bounds_check flag */
116 0x20000, /* Ndr library version */
118 0x50100a4, /* MIDL Version 5.1.164 */
120 NULL,
121 0, /* notify & notify_flag routine table */
122 1, /* Flags */
123 0, /* Reserved3 */
124 0, /* Reserved4 */
125 0 /* Reserved5 */
128 static HRESULT WINAPI if1_fn1_Proxy(void *This)
130 return S_OK;
133 static void __RPC_STUB if1_fn1_Stub(
134 IRpcStubBuffer *This,
135 IRpcChannelBuffer *_pRpcChannelBuffer,
136 PRPC_MESSAGE _pRpcMessage,
137 DWORD *_pdwStubPhase)
139 trace("fn1 stub\n");
142 static HRESULT WINAPI if1_fn2_Proxy(void *This)
144 return S_OK;
147 static void __RPC_STUB if1_fn2_Stub(
148 IRpcStubBuffer *This,
149 IRpcChannelBuffer *_pRpcChannelBuffer,
150 PRPC_MESSAGE _pRpcMessage,
151 DWORD *_pdwStubPhase)
153 trace("fn2 stub\n");
156 static CINTERFACE_PROXY_VTABLE(5) if1_proxy_vtbl =
158 { &IID_if1 },
159 { IUnknown_QueryInterface_Proxy,
160 IUnknown_AddRef_Proxy,
161 IUnknown_Release_Proxy ,
162 if1_fn1_Proxy,
163 if1_fn2_Proxy
168 static const unsigned short if1_FormatStringOffsetTable[] =
174 static const MIDL_SERVER_INFO if1_server_info =
176 &Object_StubDesc,
178 __MIDL_ProcFormatString.Format,
179 &if1_FormatStringOffsetTable[-3],
186 static const PRPC_STUB_FUNCTION if1_table[] =
188 if1_fn1_Stub,
189 if1_fn2_Stub
192 static CInterfaceStubVtbl if1_stub_vtbl =
195 &IID_if1,
196 &if1_server_info,
198 &if1_table[-3]
201 CStdStubBuffer_QueryInterface,
202 CStdStubBuffer_AddRef,
203 test_CStdStubBuffer_Release,
204 CStdStubBuffer_Connect,
205 CStdStubBuffer_Disconnect,
206 CStdStubBuffer_Invoke,
207 CStdStubBuffer_IsIIDSupported,
208 CStdStubBuffer_CountRefs,
209 CStdStubBuffer_DebugServerQueryInterface,
210 CStdStubBuffer_DebugServerRelease
214 static CINTERFACE_PROXY_VTABLE(13) if2_proxy_vtbl =
216 { &IID_if2 },
217 { IUnknown_QueryInterface_Proxy,
218 IUnknown_AddRef_Proxy,
219 IUnknown_Release_Proxy ,
233 static const unsigned short if2_FormatStringOffsetTable[] =
235 (unsigned short) -1,
236 (unsigned short) -1,
237 (unsigned short) -1,
238 (unsigned short) -1,
239 (unsigned short) -1,
240 (unsigned short) -1,
241 (unsigned short) -1,
242 (unsigned short) -1,
243 (unsigned short) -1,
244 (unsigned short) -1,
248 static const MIDL_SERVER_INFO if2_server_info =
250 &Object_StubDesc,
252 __MIDL_ProcFormatString.Format,
253 &if2_FormatStringOffsetTable[-3],
260 static const PRPC_STUB_FUNCTION if2_table[] =
262 STUB_FORWARDING_FUNCTION,
263 STUB_FORWARDING_FUNCTION,
264 STUB_FORWARDING_FUNCTION,
265 STUB_FORWARDING_FUNCTION,
266 STUB_FORWARDING_FUNCTION,
267 STUB_FORWARDING_FUNCTION,
268 STUB_FORWARDING_FUNCTION,
269 STUB_FORWARDING_FUNCTION,
270 STUB_FORWARDING_FUNCTION,
271 STUB_FORWARDING_FUNCTION
274 static CInterfaceStubVtbl if2_stub_vtbl =
277 &IID_if2,
278 &if2_server_info,
280 &if2_table[-3]
282 { 0, 0, test_CStdStubBuffer2_Release, 0, 0, 0, 0, 0, 0, 0 }
285 static CINTERFACE_PROXY_VTABLE(5) if3_proxy_vtbl =
287 { &IID_if3 },
288 { IUnknown_QueryInterface_Proxy,
289 IUnknown_AddRef_Proxy,
290 IUnknown_Release_Proxy ,
291 if1_fn1_Proxy,
297 static const unsigned short if3_FormatStringOffsetTable[] =
303 static const MIDL_SERVER_INFO if3_server_info =
305 &Object_StubDesc,
307 __MIDL_ProcFormatString.Format,
308 &if3_FormatStringOffsetTable[-3],
314 static CInterfaceStubVtbl if3_stub_vtbl =
317 &IID_if3,
318 &if3_server_info,
320 &if1_table[-3]
322 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
325 static CINTERFACE_PROXY_VTABLE(7) if4_proxy_vtbl =
327 { &IID_if4 },
328 { IUnknown_QueryInterface_Proxy,
329 IUnknown_AddRef_Proxy,
330 IUnknown_Release_Proxy ,
338 static const unsigned short if4_FormatStringOffsetTable[] =
340 (unsigned short) -1,
341 (unsigned short) -1,
342 (unsigned short) -1,
343 (unsigned short) -1,
347 static const MIDL_SERVER_INFO if4_server_info =
349 &Object_StubDesc,
351 __MIDL_ProcFormatString.Format,
352 &if4_FormatStringOffsetTable[-3],
358 static CInterfaceStubVtbl if4_stub_vtbl =
361 &IID_if4,
362 &if4_server_info,
364 &if2_table[-3]
366 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
369 static const CInterfaceProxyVtbl *cstub_ProxyVtblList[] =
371 (const CInterfaceProxyVtbl *) &if1_proxy_vtbl,
372 (const CInterfaceProxyVtbl *) &if2_proxy_vtbl,
373 (const CInterfaceProxyVtbl *) &if3_proxy_vtbl,
374 (const CInterfaceProxyVtbl *) &if4_proxy_vtbl,
375 NULL
378 static const CInterfaceStubVtbl *cstub_StubVtblList[] =
380 &if1_stub_vtbl,
381 &if2_stub_vtbl,
382 &if3_stub_vtbl,
383 &if4_stub_vtbl,
384 NULL
387 static PCInterfaceName const if_name_list[] =
389 "if1",
390 "if2",
391 "if3",
392 "if4",
393 NULL
396 static const IID *base_iid_list[] =
398 NULL,
399 &IID_ITypeLib,
400 NULL,
401 &IID_IDispatch,
402 NULL
405 #define cstub_CHECK_IID(n) IID_GENERIC_CHECK_IID( cstub, pIID, n)
407 static int __stdcall iid_lookup( const IID * pIID, int * pIndex )
409 IID_BS_LOOKUP_SETUP
411 IID_BS_LOOKUP_INITIAL_TEST( cstub, 4, 4 )
412 IID_BS_LOOKUP_NEXT_TEST( cstub, 2 )
413 IID_BS_LOOKUP_NEXT_TEST( cstub, 1 )
414 IID_BS_LOOKUP_RETURN_RESULT( cstub, 4, *pIndex )
419 static BOOL check_address(void *actual, void *expected)
421 static void *ole32_start = NULL;
422 static void *ole32_end = NULL;
423 static void *combase_start = NULL;
424 static void *combase_end = NULL;
426 if (actual == expected)
427 return TRUE;
429 /* On Win7, actual can be located inside ole32.dll */
430 if (ole32_start == NULL || ole32_end == NULL)
432 PIMAGE_NT_HEADERS nt_headers;
433 ole32_start = (void *) GetModuleHandleA("ole32.dll");
434 if (ole32_start == NULL)
435 return FALSE;
436 nt_headers = (PIMAGE_NT_HEADERS)((char *) ole32_start + ((PIMAGE_DOS_HEADER) ole32_start)->e_lfanew);
437 ole32_end = (void *)((char *) ole32_start + nt_headers->OptionalHeader.SizeOfImage);
440 if (ole32_start <= actual && actual < ole32_end)
441 return TRUE;
443 /* On Win8, actual can be located inside combase.dll */
444 if (combase_start == NULL || combase_end == NULL)
446 PIMAGE_NT_HEADERS nt_headers;
447 combase_start = (void *) GetModuleHandleA("combase.dll");
448 if (combase_start == NULL)
449 return FALSE;
450 nt_headers = (PIMAGE_NT_HEADERS)((char *) combase_start + ((PIMAGE_DOS_HEADER) combase_start)->e_lfanew);
451 combase_end = (void *)((char *) combase_start + nt_headers->OptionalHeader.SizeOfImage);
454 return (combase_start <= actual && actual < combase_end);
457 static const ExtendedProxyFileInfo my_proxy_file_info =
459 (const PCInterfaceProxyVtblList *) &cstub_ProxyVtblList,
460 (const PCInterfaceStubVtblList *) &cstub_StubVtblList,
461 (const PCInterfaceName *) &if_name_list,
462 (const IID **) &base_iid_list,
463 &iid_lookup,
466 NULL,
472 static const ProxyFileInfo *proxy_file_list[] = {
473 &my_proxy_file_info,
474 NULL
478 static IPSFactoryBuffer *test_NdrDllGetClassObject(void)
480 HMODULE rpcrt4 = GetModuleHandleA("rpcrt4.dll");
481 IPSFactoryBuffer *ppsf = NULL;
482 const PCInterfaceProxyVtblList* proxy_vtbl;
483 const PCInterfaceStubVtblList* stub_vtbl;
484 const CLSID CLSID_Unknown = {0x45678, 0x1234, 0x6666, {0xff, 0x67, 0x45, 0x98, 0x76, 0x12, 0x34, 0x56}};
485 static const GUID * const interfaces[] = { &IID_if1, &IID_if2, &IID_if3, &IID_if4 };
486 UINT i;
487 HRESULT r;
488 HMODULE hmod = GetModuleHandleA("rpcrt4.dll");
489 void *CStd_QueryInterface = GetProcAddress(hmod, "CStdStubBuffer_QueryInterface");
490 void *CStd_AddRef = GetProcAddress(hmod, "CStdStubBuffer_AddRef");
491 void *CStd_Release = GetProcAddress(hmod, "NdrCStdStubBuffer_Release");
492 void *CStd_Connect = GetProcAddress(hmod, "CStdStubBuffer_Connect");
493 void *CStd_Disconnect = GetProcAddress(hmod, "CStdStubBuffer_Disconnect");
494 void *CStd_Invoke = GetProcAddress(hmod, "CStdStubBuffer_Invoke");
495 void *CStd_IsIIDSupported = GetProcAddress(hmod, "CStdStubBuffer_IsIIDSupported");
496 void *CStd_CountRefs = GetProcAddress(hmod, "CStdStubBuffer_CountRefs");
497 void *CStd_DebugServerQueryInterface = GetProcAddress(hmod, "CStdStubBuffer_DebugServerQueryInterface");
498 void *CStd_DebugServerRelease = GetProcAddress(hmod, "CStdStubBuffer_DebugServerRelease");
500 r = NdrDllGetClassObject(&CLSID_Unknown, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
501 &CLSID_psfact, &PSFactoryBuffer);
502 ok(r == CLASS_E_CLASSNOTAVAILABLE, "NdrDllGetClassObject with unknown clsid should have returned CLASS_E_CLASSNOTAVAILABLE instead of 0x%lx\n", r);
503 ok(ppsf == NULL, "NdrDllGetClassObject should have set ppsf to NULL on failure\n");
505 r = NdrDllGetClassObject(&CLSID_psfact, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
506 &CLSID_psfact, &PSFactoryBuffer);
508 ok(r == S_OK, "ret %08lx\n", r);
509 ok(ppsf != NULL, "ppsf == NULL\n");
511 proxy_vtbl = PSFactoryBuffer.pProxyFileList[0]->pProxyVtblList;
512 stub_vtbl = PSFactoryBuffer.pProxyFileList[0]->pStubVtblList;
513 ok(PSFactoryBuffer.pProxyFileList == proxy_file_list, "pfl not the same\n");
514 ok(proxy_vtbl == (PCInterfaceProxyVtblList *) &cstub_ProxyVtblList, "proxy vtbllist not the same\n");
515 ok(stub_vtbl == (PCInterfaceStubVtblList *) &cstub_StubVtblList, "stub vtbllist not the same\n");
517 /* if1 is non-delegating, if2 is delegating, if3 is non-delegating
518 but I've zero'ed the vtbl entries, similarly if4 is delegating
519 with zero'ed vtbl entries */
521 #define VTBL_TEST_NOT_CHANGE_TO(name, i) \
522 ok(stub_vtbl[i]->Vtbl.name != CStd_##name, #name "vtbl %d updated %p %p\n", \
523 i, stub_vtbl[i]->Vtbl.name, CStd_##name )
524 #define VTBL_TEST_CHANGE_TO(name, i) \
525 ok(check_address(stub_vtbl[i]->Vtbl.name, CStd_##name), #name "vtbl %d not updated %p %p\n", \
526 i, stub_vtbl[i]->Vtbl.name, CStd_##name )
527 #define VTBL_TEST_ZERO(name, i) \
528 ok(stub_vtbl[i]->Vtbl.name == NULL, #name "vtbl %d not null %p\n", \
529 i, stub_vtbl[i]->Vtbl.name )
531 VTBL_TEST_NOT_CHANGE_TO(QueryInterface, 0);
532 VTBL_TEST_NOT_CHANGE_TO(AddRef, 0);
533 VTBL_TEST_NOT_CHANGE_TO(Release, 0);
534 VTBL_TEST_NOT_CHANGE_TO(Connect, 0);
535 VTBL_TEST_NOT_CHANGE_TO(Disconnect, 0);
536 VTBL_TEST_NOT_CHANGE_TO(Invoke, 0);
537 VTBL_TEST_NOT_CHANGE_TO(IsIIDSupported, 0);
538 VTBL_TEST_NOT_CHANGE_TO(CountRefs, 0);
539 VTBL_TEST_NOT_CHANGE_TO(DebugServerQueryInterface, 0);
540 VTBL_TEST_NOT_CHANGE_TO(DebugServerRelease, 0);
542 VTBL_TEST_CHANGE_TO(QueryInterface, 1);
543 VTBL_TEST_CHANGE_TO(AddRef, 1);
544 VTBL_TEST_NOT_CHANGE_TO(Release, 1);
545 VTBL_TEST_NOT_CHANGE_TO(Connect, 1);
546 VTBL_TEST_NOT_CHANGE_TO(Disconnect, 1);
547 VTBL_TEST_CHANGE_TO(Invoke, 1);
548 VTBL_TEST_CHANGE_TO(IsIIDSupported, 1);
549 VTBL_TEST_NOT_CHANGE_TO(CountRefs, 1);
550 VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 1);
551 VTBL_TEST_CHANGE_TO(DebugServerRelease, 1);
553 VTBL_TEST_CHANGE_TO(QueryInterface, 2);
554 VTBL_TEST_CHANGE_TO(AddRef, 2);
555 VTBL_TEST_ZERO(Release, 2);
556 VTBL_TEST_CHANGE_TO(Connect, 2);
557 VTBL_TEST_CHANGE_TO(Disconnect, 2);
558 VTBL_TEST_CHANGE_TO(Invoke, 2);
559 VTBL_TEST_CHANGE_TO(IsIIDSupported, 2);
560 VTBL_TEST_CHANGE_TO(CountRefs, 2);
561 VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 2);
562 VTBL_TEST_CHANGE_TO(DebugServerRelease, 2);
564 VTBL_TEST_CHANGE_TO(QueryInterface, 3);
565 VTBL_TEST_CHANGE_TO(AddRef, 3);
566 VTBL_TEST_ZERO(Release, 3);
567 VTBL_TEST_NOT_CHANGE_TO(Connect, 3);
568 VTBL_TEST_NOT_CHANGE_TO(Disconnect, 3);
569 VTBL_TEST_CHANGE_TO(Invoke, 3);
570 VTBL_TEST_CHANGE_TO(IsIIDSupported, 3);
571 VTBL_TEST_NOT_CHANGE_TO(CountRefs, 3);
572 VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 3);
573 VTBL_TEST_CHANGE_TO(DebugServerRelease, 3);
575 #define VTBL_PROXY_TEST(i,num,ptr) \
576 ok( check_address(proxy_vtbl[i]->Vtbl[num], (ptr)), "wrong proxy %u func %u %p/%p\n", \
577 (i), (num), proxy_vtbl[i]->Vtbl[num], (ptr) )
578 #define VTBL_PROXY_TEST_NOT_ZERO(i,num) \
579 ok( proxy_vtbl[i]->Vtbl[num] != NULL, "wrong proxy %u func %u is NULL\n", (i), (num))
581 VTBL_PROXY_TEST(0, 0, IUnknown_QueryInterface_Proxy);
582 VTBL_PROXY_TEST(0, 1, IUnknown_AddRef_Proxy);
583 VTBL_PROXY_TEST(0, 2, IUnknown_Release_Proxy);
584 VTBL_PROXY_TEST(0, 3, if1_fn1_Proxy);
585 VTBL_PROXY_TEST(0, 4, if1_fn2_Proxy);
587 VTBL_PROXY_TEST(1, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy"));
588 VTBL_PROXY_TEST(1, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy"));
589 VTBL_PROXY_TEST(1, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy"));
590 VTBL_PROXY_TEST_NOT_ZERO(1, 3);
591 VTBL_PROXY_TEST_NOT_ZERO(1, 4);
592 VTBL_PROXY_TEST_NOT_ZERO(1, 5);
593 VTBL_PROXY_TEST_NOT_ZERO(1, 6);
594 VTBL_PROXY_TEST_NOT_ZERO(1, 7);
595 VTBL_PROXY_TEST_NOT_ZERO(1, 8);
596 VTBL_PROXY_TEST_NOT_ZERO(1, 9);
597 VTBL_PROXY_TEST_NOT_ZERO(1, 10);
598 VTBL_PROXY_TEST_NOT_ZERO(1, 11);
599 VTBL_PROXY_TEST_NOT_ZERO(1, 12);
601 VTBL_PROXY_TEST(2, 0, IUnknown_QueryInterface_Proxy);
602 VTBL_PROXY_TEST(2, 1, IUnknown_AddRef_Proxy);
603 VTBL_PROXY_TEST(2, 2, IUnknown_Release_Proxy);
604 VTBL_PROXY_TEST(2, 3, if1_fn1_Proxy);
605 todo_wine VTBL_PROXY_TEST_NOT_ZERO(2, 4);
607 VTBL_PROXY_TEST(3, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy"));
608 VTBL_PROXY_TEST(3, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy"));
609 VTBL_PROXY_TEST(3, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy"));
610 VTBL_PROXY_TEST_NOT_ZERO(3, 3);
611 VTBL_PROXY_TEST_NOT_ZERO(3, 4);
612 VTBL_PROXY_TEST_NOT_ZERO(3, 5);
613 VTBL_PROXY_TEST_NOT_ZERO(3, 6);
615 #undef VTBL_TEST_NOT_CHANGE_TO
616 #undef VTBL_TEST_CHANGE_TO
617 #undef VTBL_TEST_ZERO
618 #undef VTBL_PROXY_TEST
619 #undef VTBL_PROXY_TEST_NOT_ZERO
621 for (i = 0; i < ARRAY_SIZE(interfaces); i++)
622 ok( proxy_vtbl[i]->header.piid == interfaces[i],
623 "wrong proxy %u iid %p/%p\n", i, proxy_vtbl[i]->header.piid, interfaces[i] );
625 ok(PSFactoryBuffer.RefCount == 1, "ref count %ld\n", PSFactoryBuffer.RefCount);
626 IPSFactoryBuffer_Release(ppsf);
628 /* One can also search by IID */
629 r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
630 &CLSID_psfact, &PSFactoryBuffer);
631 ok(r == S_OK, "ret %08lx\n", r);
632 ok(ppsf != NULL, "ppsf == NULL\n");
633 IPSFactoryBuffer_Release(ppsf);
635 r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
636 NULL, &PSFactoryBuffer);
637 ok(r == S_OK, "ret %08lx\n", r);
638 ok(ppsf != NULL, "ppsf == NULL\n");
639 IPSFactoryBuffer_Release(ppsf);
641 /* but only if the PS factory implements it */
642 r = NdrDllGetClassObject(&IID_IDispatch, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
643 &CLSID_psfact, &PSFactoryBuffer);
644 ok(r == CLASS_E_CLASSNOTAVAILABLE, "ret %08lx\n", r);
646 /* Create it again to return */
647 r = NdrDllGetClassObject(&CLSID_psfact, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
648 &CLSID_psfact, &PSFactoryBuffer);
649 ok(r == S_OK, "ret %08lx\n", r);
650 ok(ppsf != NULL, "ppsf == NULL\n");
652 /* Because this PS factory is not loaded as a dll in the normal way, Windows 8 / 10
653 get confused and will crash when one of the proxies for the delegated ifaces is created.
654 Registering the ifaces fixes this (in fact calling CoRegisterPSClsid() with any IID / CLSID is enough). */
656 r = CoRegisterPSClsid(&IID_if1, &CLSID_psfact);
657 ok(r == S_OK, "ret %08lx\n", r);
658 r = CoRegisterPSClsid(&IID_if2, &CLSID_psfact);
659 ok(r == S_OK, "ret %08lx\n", r);
660 r = CoRegisterPSClsid(&IID_if3, &CLSID_psfact);
661 ok(r == S_OK, "ret %08lx\n", r);
662 r = CoRegisterPSClsid(&IID_if4, &CLSID_psfact);
663 ok(r == S_OK, "ret %08lx\n", r);
665 return ppsf;
668 static int base_buffer_invoke_called;
669 static HRESULT WINAPI base_buffer_Invoke(IRpcStubBuffer *This, RPCOLEMESSAGE *msg, IRpcChannelBuffer *channel)
671 base_buffer_invoke_called++;
672 ok(msg == (RPCOLEMESSAGE*)0xcafebabe, "msg ptr changed\n");
673 ok(channel == (IRpcChannelBuffer*)0xdeadbeef, "channel ptr changed\n");
674 return S_OK; /* returning any failure here results in an exception */
677 static IRpcStubBufferVtbl base_buffer_vtbl = {
678 (void*)0xcafebab0,
679 (void*)0xcafebab1,
680 (void*)0xcafebab2,
681 (void*)0xcafebab3,
682 (void*)0xcafebab4,
683 base_buffer_Invoke,
684 (void*)0xcafebab6,
685 (void*)0xcafebab7,
686 (void*)0xcafebab8,
687 (void*)0xcafebab9
690 static void test_NdrStubForwardingFunction(void)
692 void *This[5];
693 void *real_this;
694 IRpcChannelBuffer *channel = (IRpcChannelBuffer*)0xdeadbeef;
695 RPC_MESSAGE *msg = (RPC_MESSAGE*)0xcafebabe;
696 DWORD *phase = (DWORD*)0x12345678;
697 IRpcStubBufferVtbl *base_buffer_vtbl_ptr = &base_buffer_vtbl;
698 IRpcStubBuffer *base_stub_buffer = (IRpcStubBuffer*)&base_buffer_vtbl_ptr;
700 memset(This, 0xcc, sizeof(This));
701 This[0] = base_stub_buffer;
702 real_this = &This[1];
704 NdrStubForwardingFunction( real_this, channel, msg, phase );
705 ok(base_buffer_invoke_called == 1, "base_buffer_invoke called %d times\n", base_buffer_invoke_called);
709 static IRpcStubBuffer *create_stub(IPSFactoryBuffer *ppsf, REFIID iid, IUnknown *obj, HRESULT expected_result)
711 IRpcStubBuffer *pstub = NULL;
712 HRESULT r;
714 r = IPSFactoryBuffer_CreateStub(ppsf, iid, obj, &pstub);
715 ok(r == expected_result, "CreateStub returned %08lx expected %08lx\n", r, expected_result);
716 return pstub;
719 static HRESULT WINAPI create_stub_test_QI(IUnknown *This, REFIID iid, void **ppv)
721 ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
722 *ppv = (void*)0xdeadbeef;
723 return S_OK;
726 static IUnknownVtbl create_stub_test_vtbl =
728 create_stub_test_QI,
729 NULL,
730 NULL
733 static HRESULT WINAPI create_stub_test_fail_QI(IUnknown *This, REFIID iid, void **ppv)
735 ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
736 *ppv = NULL;
737 return E_NOINTERFACE;
740 static IUnknownVtbl create_stub_test_fail_vtbl =
742 create_stub_test_fail_QI,
743 NULL,
744 NULL
747 struct dummy_unknown
749 IUnknown IUnknown_iface;
750 LONG ref;
753 static inline struct dummy_unknown *impl_from_IUnknown(IUnknown *iface)
755 return CONTAINING_RECORD(iface, struct dummy_unknown, IUnknown_iface);
758 static HRESULT WINAPI dummy_QueryInterface(IUnknown *This, REFIID iid, void **ppv)
760 *ppv = NULL;
761 return E_NOINTERFACE;
764 static ULONG WINAPI dummy_AddRef(LPUNKNOWN iface)
766 struct dummy_unknown *this = impl_from_IUnknown(iface);
767 return InterlockedIncrement( &this->ref );
770 static ULONG WINAPI dummy_Release(LPUNKNOWN iface)
772 struct dummy_unknown *this = impl_from_IUnknown(iface);
773 return InterlockedDecrement( &this->ref );
776 static IUnknownVtbl dummy_unknown_vtbl =
778 dummy_QueryInterface,
779 dummy_AddRef,
780 dummy_Release
782 static struct dummy_unknown dummy_unknown = { { &dummy_unknown_vtbl }, 0 };
784 static void create_proxy_test( IPSFactoryBuffer *ppsf, REFIID iid, const void *expected_vtbl )
786 IRpcProxyBuffer *proxy = NULL;
787 IUnknown *iface = NULL;
788 HRESULT r;
789 ULONG count;
791 r = IPSFactoryBuffer_CreateProxy(ppsf, NULL, iid, &proxy, (void **)&iface);
792 ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %lx\n", r );
793 ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
794 count = IUnknown_Release( iface );
795 ok( count == 1, "wrong refcount %lu\n", count );
796 count = IRpcProxyBuffer_Release( proxy );
797 ok( count == 0, "wrong refcount %lu\n", count );
799 dummy_unknown.ref = 4;
800 r = IPSFactoryBuffer_CreateProxy(ppsf, &dummy_unknown.IUnknown_iface, iid, &proxy,
801 (void **)&iface);
802 ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %lx\n", r );
803 ok( dummy_unknown.ref == 5, "wrong refcount %lu\n", dummy_unknown.ref );
804 ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
805 count = IUnknown_Release( iface );
806 ok( count == 4, "wrong refcount %lu\n", count );
807 ok( dummy_unknown.ref == 4, "wrong refcount %lu\n", dummy_unknown.ref );
808 count = IRpcProxyBuffer_Release( proxy );
809 ok( count == 0, "wrong refcount %lu\n", count );
810 ok( dummy_unknown.ref == 4, "wrong refcount %lu\n", dummy_unknown.ref );
813 static void test_CreateProxy( IPSFactoryBuffer *ppsf )
815 create_proxy_test( ppsf, &IID_if1, if1_proxy_vtbl.Vtbl );
816 create_proxy_test( ppsf, &IID_if2, if2_proxy_vtbl.Vtbl );
817 create_proxy_test( ppsf, &IID_if3, if3_proxy_vtbl.Vtbl );
818 create_proxy_test( ppsf, &IID_if4, if4_proxy_vtbl.Vtbl );
821 static void test_CreateStub(IPSFactoryBuffer *ppsf)
823 IUnknownVtbl *vtbl = &create_stub_test_vtbl;
824 IUnknown *obj = (IUnknown*)&vtbl;
825 IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
826 CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
827 const CInterfaceStubHeader *header = &CONTAINING_RECORD(cstd_stub->lpVtbl, const CInterfaceStubVtbl, Vtbl)->header;
829 ok(IsEqualIID(header->piid, &IID_if1), "header iid differs\n");
830 ok(cstd_stub->RefCount == 1, "ref count %ld\n", cstd_stub->RefCount);
831 /* 0xdeadbeef returned from create_stub_test_QI */
832 ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
833 ok(cstd_stub->pPSFactory != NULL, "pPSFactory was NULL\n");
834 cstd_stub->pvServerObject = NULL;
835 IRpcStubBuffer_Release(pstub);
837 vtbl = &create_stub_test_fail_vtbl;
838 pstub = create_stub(ppsf, &IID_if1, obj, E_NOINTERFACE);
839 ok(pstub == S_OK, "create_stub failed: %lu\n", GetLastError());
843 static HRESULT WINAPI connect_test_orig_QI(IUnknown *This, REFIID iid, void **ppv)
845 ok(IsEqualIID(iid, &IID_if1) ||
846 IsEqualIID(iid, &IID_if2), "incorrect iid\n");
847 *ppv = (void*)This;
848 return S_OK;
851 static int connect_test_orig_release_called;
852 static ULONG WINAPI connect_test_orig_release(IUnknown *This)
854 connect_test_orig_release_called++;
855 return 0;
858 static IUnknownVtbl connect_test_orig_vtbl =
860 connect_test_orig_QI,
861 NULL,
862 connect_test_orig_release
865 static HRESULT WINAPI connect_test_new_QI(IUnknown *This, REFIID iid, void **ppv)
867 ok(IsEqualIID(iid, &IID_if1) ||
868 IsEqualIID(iid, &IID_if2), "incorrect iid\n");
869 *ppv = (void*)0xcafebabe;
870 return S_OK;
873 static IUnknownVtbl connect_test_new_vtbl =
875 connect_test_new_QI,
876 NULL,
877 NULL
880 static HRESULT WINAPI connect_test_new_fail_QI(IUnknown *This, REFIID iid, void **ppv)
882 ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
883 *ppv = (void*)0xdeadbeef;
884 return E_NOINTERFACE;
887 static IUnknownVtbl connect_test_new_fail_vtbl =
889 connect_test_new_fail_QI,
890 NULL,
891 NULL
894 static int connect_test_base_Connect_called;
895 static HRESULT WINAPI connect_test_base_Connect(IRpcStubBuffer *pstub, IUnknown *obj)
897 connect_test_base_Connect_called++;
898 ok(*(void**)obj == (void*)0xbeefcafe, "unexpected obj %p\n", obj);
899 return S_OK;
902 static IRpcStubBufferVtbl connect_test_base_stub_buffer_vtbl =
904 (void*)0xcafebab0,
905 (void*)0xcafebab1,
906 (void*)0xcafebab2,
907 connect_test_base_Connect,
908 (void*)0xcafebab4,
909 (void*)0xcafebab5,
910 (void*)0xcafebab6,
911 (void*)0xcafebab7,
912 (void*)0xcafebab8,
913 (void*)0xcafebab9
916 static void test_Connect(IPSFactoryBuffer *ppsf)
918 IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
919 IUnknownVtbl *new_vtbl = &connect_test_new_vtbl;
920 IUnknownVtbl *new_fail_vtbl = &connect_test_new_fail_vtbl;
921 IUnknown *obj = (IUnknown*)&orig_vtbl;
922 IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
923 CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
924 IRpcStubBufferVtbl *base_stub_buf_vtbl = &connect_test_base_stub_buffer_vtbl;
925 HRESULT r;
927 obj = (IUnknown*)&new_vtbl;
928 r = IRpcStubBuffer_Connect(pstub, obj);
929 ok(r == S_OK, "r %08lx\n", r);
930 ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
931 ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
933 cstd_stub->pvServerObject = (IUnknown*)&orig_vtbl;
934 obj = (IUnknown*)&new_fail_vtbl;
935 r = IRpcStubBuffer_Connect(pstub, obj);
936 ok(r == E_NOINTERFACE, "r %08lx\n", r);
937 ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
938 ok(connect_test_orig_release_called == 2, "release called %d\n", connect_test_orig_release_called);
940 /* Now use a delegated stub.
942 We know from the NdrStubForwardFunction test that
943 (void**)pstub-1 is the base interface stub buffer. This shows
944 that (void**)pstub-2 contains the address of a vtable that gets
945 passed to the base interface's Connect method. Note that
946 (void**)pstub-2 itself gets passed to Connect and not
947 *((void**)pstub-2), so it should contain the vtable ptr and not
948 an interface ptr. */
950 obj = (IUnknown*)&orig_vtbl;
951 pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
952 *((void**)pstub-1) = &base_stub_buf_vtbl;
953 *((void**)pstub-2) = (void*)0xbeefcafe;
955 obj = (IUnknown*)&new_vtbl;
956 r = IRpcStubBuffer_Connect(pstub, obj);
957 ok(r == S_OK, "r %08lx\n", r);
958 ok(connect_test_base_Connect_called == 1, "connect_test_bsae_Connect called %d times\n",
959 connect_test_base_Connect_called);
960 ok(connect_test_orig_release_called == 3, "release called %d\n", connect_test_orig_release_called);
961 cstd_stub = (CStdStubBuffer*)pstub;
962 ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
965 static void test_Disconnect(IPSFactoryBuffer *ppsf)
967 IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
968 IUnknown *obj = (IUnknown*)&orig_vtbl;
969 IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
970 CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
972 connect_test_orig_release_called = 0;
973 IRpcStubBuffer_Disconnect(pstub);
974 ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
975 ok(cstd_stub->pvServerObject == NULL, "pvServerObject %p\n", cstd_stub->pvServerObject);
976 IRpcStubBuffer_Release(pstub);
980 static int release_test_psfacbuf_release_called;
981 static ULONG WINAPI release_test_pretend_psfacbuf_release(IUnknown *pUnk)
983 release_test_psfacbuf_release_called++;
984 return 1;
987 static IUnknownVtbl release_test_pretend_psfacbuf_vtbl =
989 NULL,
990 NULL,
991 release_test_pretend_psfacbuf_release
994 static void test_Release(IPSFactoryBuffer *ppsf)
996 LONG facbuf_refs;
997 IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
998 IUnknown *obj = (IUnknown*)&orig_vtbl;
999 IUnknownVtbl *pretend_psfacbuf_vtbl = &release_test_pretend_psfacbuf_vtbl;
1000 IUnknown *pretend_psfacbuf = (IUnknown *)&pretend_psfacbuf_vtbl;
1001 IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
1002 CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
1004 facbuf_refs = PSFactoryBuffer.RefCount;
1006 /* This shows that NdrCStdStubBuffer_Release doesn't call Disconnect */
1007 ok(cstd_stub->RefCount == 1, "ref count %ld\n", cstd_stub->RefCount);
1008 connect_test_orig_release_called = 0;
1009 IRpcStubBuffer_Release(pstub);
1010 todo_wine {
1011 ok(connect_test_orig_release_called == 0, "release called %d\n", connect_test_orig_release_called);
1013 ok(PSFactoryBuffer.RefCount == facbuf_refs - 1, "factory buffer refs %ld orig %ld\n", PSFactoryBuffer.RefCount, facbuf_refs);
1015 /* This shows that NdrCStdStubBuffer_Release calls Release on its 2nd arg, rather than on This->pPSFactory
1016 (which are usually the same and indeed it's odd that _Release requires this 2nd arg). */
1017 pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
1018 ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %ld orig %ld\n", PSFactoryBuffer.RefCount, facbuf_refs);
1019 NdrCStdStubBuffer_Release(pstub, (IPSFactoryBuffer*)pretend_psfacbuf);
1020 ok(release_test_psfacbuf_release_called == 1, "pretend_psfacbuf_release called %d\n", release_test_psfacbuf_release_called);
1021 ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %ld orig %ld\n", PSFactoryBuffer.RefCount, facbuf_refs);
1024 static HRESULT WINAPI delegating_invoke_test_QI(ITypeLib *pUnk, REFIID iid, void** ppv)
1027 *ppv = pUnk;
1028 return S_OK;
1031 static ULONG WINAPI delegating_invoke_test_addref(ITypeLib *pUnk)
1033 return 1;
1036 static ULONG WINAPI delegating_invoke_test_release(ITypeLib *pUnk)
1038 return 1;
1041 static UINT WINAPI delegating_invoke_test_get_type_info_count(ITypeLib *pUnk)
1043 return 0xabcdef;
1046 static ITypeLibVtbl delegating_invoke_test_obj_vtbl =
1048 delegating_invoke_test_QI,
1049 delegating_invoke_test_addref,
1050 delegating_invoke_test_release,
1051 delegating_invoke_test_get_type_info_count,
1052 NULL,
1053 NULL,
1054 NULL,
1055 NULL,
1056 NULL,
1057 NULL,
1058 NULL,
1059 NULL,
1060 NULL
1063 static HRESULT WINAPI delegating_invoke_chan_query_interface(IRpcChannelBuffer *pchan,
1064 REFIID iid,
1065 void **ppv)
1067 ok(0, "call to QueryInterface not expected\n");
1068 return E_NOINTERFACE;
1071 static ULONG WINAPI delegating_invoke_chan_add_ref(IRpcChannelBuffer *pchan)
1073 return 2;
1076 static ULONG WINAPI delegating_invoke_chan_release(IRpcChannelBuffer *pchan)
1078 return 1;
1081 static HRESULT WINAPI delegating_invoke_chan_get_buffer(IRpcChannelBuffer *pchan,
1082 RPCOLEMESSAGE *msg,
1083 REFIID iid)
1085 msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->cbBuffer);
1086 return S_OK;
1089 static HRESULT WINAPI delegating_invoke_chan_send_receive(IRpcChannelBuffer *pchan,
1090 RPCOLEMESSAGE *pMessage,
1091 ULONG *pStatus)
1093 ok(0, "call to SendReceive not expected\n");
1094 return E_NOTIMPL;
1097 static HRESULT WINAPI delegating_invoke_chan_free_buffer(IRpcChannelBuffer *pchan,
1098 RPCOLEMESSAGE *pMessage)
1100 ok(0, "call to FreeBuffer not expected\n");
1101 return E_NOTIMPL;
1104 static HRESULT WINAPI delegating_invoke_chan_get_dest_ctx(IRpcChannelBuffer *pchan,
1105 DWORD *pdwDestContext,
1106 void **ppvDestContext)
1108 *pdwDestContext = MSHCTX_LOCAL;
1109 *ppvDestContext = NULL;
1110 return S_OK;
1113 static HRESULT WINAPI delegating_invoke_chan_is_connected(IRpcChannelBuffer *pchan)
1115 ok(0, "call to IsConnected not expected\n");
1116 return E_NOTIMPL;
1119 static IRpcChannelBufferVtbl delegating_invoke_test_rpc_chan_vtbl =
1121 delegating_invoke_chan_query_interface,
1122 delegating_invoke_chan_add_ref,
1123 delegating_invoke_chan_release,
1124 delegating_invoke_chan_get_buffer,
1125 delegating_invoke_chan_send_receive,
1126 delegating_invoke_chan_free_buffer,
1127 delegating_invoke_chan_get_dest_ctx,
1128 delegating_invoke_chan_is_connected
1131 static void test_delegating_Invoke(IPSFactoryBuffer *ppsf)
1133 ITypeLibVtbl *obj_vtbl = &delegating_invoke_test_obj_vtbl;
1134 IUnknown *obj = (IUnknown*)&obj_vtbl;
1135 IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
1136 IRpcChannelBufferVtbl *pchan_vtbl = &delegating_invoke_test_rpc_chan_vtbl;
1137 IRpcChannelBuffer *pchan = (IRpcChannelBuffer *)&pchan_vtbl;
1138 HRESULT r = E_FAIL;
1139 RPCOLEMESSAGE msg;
1141 memset(&msg, 0, sizeof(msg));
1142 msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
1143 msg.iMethod = 3;
1144 r = IRpcStubBuffer_Invoke(pstub, &msg, pchan);
1145 ok(r == S_OK, "ret %08lx\n", r);
1146 if(r == S_OK)
1148 ok(*(DWORD*)msg.Buffer == 0xabcdef, "buf[0] %08lx\n", *(DWORD*)msg.Buffer);
1149 ok(*((DWORD*)msg.Buffer + 1) == S_OK, "buf[1] %08lx\n", *((DWORD*)msg.Buffer + 1));
1151 /* free the buffer allocated by delegating_invoke_chan_get_buffer */
1152 HeapFree(GetProcessHeap(), 0, msg.Buffer);
1153 IRpcStubBuffer_Release(pstub);
1155 static const CInterfaceProxyVtbl *cstub_ProxyVtblList2[] =
1157 NULL
1160 static const CInterfaceStubVtbl *cstub_StubVtblList2[] =
1162 NULL
1165 static PCInterfaceName const if_name_list2[] =
1167 NULL
1170 static const IID *base_iid_list2[] =
1172 NULL,
1175 static const ExtendedProxyFileInfo my_proxy_file_info2 =
1177 (const PCInterfaceProxyVtblList *) &cstub_ProxyVtblList2,
1178 (const PCInterfaceStubVtblList *) &cstub_StubVtblList2,
1179 (const PCInterfaceName *) &if_name_list2,
1180 (const IID **) &base_iid_list2,
1181 &iid_lookup,
1184 NULL,
1190 static const ProxyFileInfo *proxy_file_list2[] = {
1191 &my_proxy_file_info2,
1192 NULL
1195 static void test_NdrDllRegisterProxy( void )
1197 HRESULT res;
1198 const ExtendedProxyFileInfo *pf;
1199 HMODULE hmod = GetModuleHandleA(NULL);
1202 res = NdrDllRegisterProxy(NULL, NULL, NULL);
1203 ok(res == E_HANDLE, "Incorrect return code %lx\n",res);
1204 pf = NULL;
1205 res = NdrDllRegisterProxy(hmod, &pf, NULL);
1206 ok(res == E_NOINTERFACE, "Incorrect return code %lx\n",res);
1207 res = NdrDllRegisterProxy(hmod, proxy_file_list2, NULL);
1208 ok(res == E_NOINTERFACE, "Incorrect return code %lx\n",res);
1209 /* This fails on Vista and Windows 7 due to permissions */
1210 res = NdrDllRegisterProxy(hmod, proxy_file_list, NULL);
1211 ok(res == S_OK || res == E_ACCESSDENIED, "NdrDllRegisterProxy failed %lx\n",res);
1212 if (res == S_OK)
1214 res = NdrDllUnregisterProxy(hmod,proxy_file_list, NULL);
1215 ok(res == S_OK, "NdrDllUnregisterProxy failed %lx\n",res);
1219 static HANDLE create_process(const char *arg)
1221 PROCESS_INFORMATION pi;
1222 STARTUPINFOA si = {0};
1223 char cmdline[200];
1224 char **argv;
1225 BOOL ret;
1227 si.cb = sizeof(si);
1228 winetest_get_mainargs(&argv);
1229 sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], arg);
1230 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1231 ok(ret, "CreateProcess failed: %lu\n", GetLastError());
1232 CloseHandle(pi.hThread);
1233 return pi.hProcess;
1236 DEFINE_GUID(CLSID_test1,0xdeadf00d,0x0001,0x44c7,0x85,0x0f,0x2a,0x0f,0x46,0x5c,0x0c,0x6c);
1238 static HRESULT WINAPI test1_QueryInterface(ITest1 *iface, REFIID iid, void **out)
1240 if (winetest_debug > 1) trace("%s\n", wine_dbgstr_guid(iid));
1241 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_ITest1))
1243 *out = iface;
1244 return S_OK;
1246 *out = NULL;
1247 return E_NOINTERFACE;
1250 static ULONG WINAPI test1_AddRef(ITest1 *iface)
1252 return 2;
1255 static ULONG WINAPI test1_Release(ITest1 *iface)
1257 return 1;
1260 static HRESULT WINAPI test1_GetClassID(ITest1 *iface, CLSID *clsid)
1262 *clsid = CLSID_test1;
1263 return S_OK;
1266 static int WINAPI test1_square(ITest1 *iface, int x)
1268 return x * x;
1271 static const ITest1Vtbl test1_vtbl =
1273 test1_QueryInterface,
1274 test1_AddRef,
1275 test1_Release,
1276 test1_GetClassID,
1277 test1_square,
1280 static HRESULT WINAPI test_cf_QueryInterface(IClassFactory *iface, REFIID iid, void **out)
1282 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory))
1284 *out = iface;
1285 return S_OK;
1287 *out = NULL;
1288 return E_NOINTERFACE;
1291 static ULONG WINAPI test_cf_AddRef(IClassFactory *iface)
1293 return 2;
1296 static ULONG WINAPI test_cf_Release(IClassFactory *iface)
1298 return 1;
1301 static HRESULT WINAPI test_cf_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out)
1303 ITest1 *obj = heap_alloc(sizeof(*obj));
1305 obj->lpVtbl = &test1_vtbl;
1307 return ITest1_QueryInterface(obj, iid, out);
1310 static HRESULT WINAPI test_cf_LockServer(IClassFactory *iface, BOOL lock)
1312 return S_OK;
1315 static const IClassFactoryVtbl test_cf_vtbl =
1317 test_cf_QueryInterface,
1318 test_cf_AddRef,
1319 test_cf_Release,
1320 test_cf_CreateInstance,
1321 test_cf_LockServer,
1324 static IClassFactory test_cf = { &test_cf_vtbl };
1326 extern CStdPSFactoryBuffer gPFactory;
1327 extern const ProxyFileInfo * aProxyFileList;
1329 static void local_server_proc(void)
1331 DWORD obj_cookie, ps_cookie, index;
1332 HANDLE stop_event, ready_event;
1333 IPSFactoryBuffer *ps;
1334 HRESULT hr;
1336 stop_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "wine_cstub_test_server_stop");
1337 ready_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "wine_cstub_test_server_ready");
1339 CoInitialize(NULL);
1341 hr = CoRegisterClassObject(&CLSID_test1, (IUnknown *)&test_cf,
1342 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &obj_cookie);
1343 ok(hr == S_OK, "got %#lx\n", hr);
1345 hr = NdrDllGetClassObject(&CLSID_test_ps, &IID_IPSFactoryBuffer, (void **)&ps,
1346 &aProxyFileList, &CLSID_test_ps, &gPFactory);
1347 ok(hr == S_OK, "got %#lx\n", hr);
1349 hr = CoRegisterClassObject(&CLSID_test_ps, (IUnknown *)ps,
1350 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &ps_cookie);
1351 ok(hr == S_OK, "got %#lx\n", hr);
1353 hr = CoRegisterPSClsid(&IID_ITest1, &CLSID_test_ps);
1354 ok(hr == S_OK, "got %#lx\n", hr);
1356 SetEvent(ready_event);
1358 hr = CoWaitForMultipleHandles(0, 1000, 1, &stop_event, &index);
1359 ok(hr == S_OK, "got %#lx\n", hr);
1360 ok(!index, "got %lu\n", index);
1362 hr = CoRevokeClassObject(ps_cookie);
1363 ok(hr == S_OK, "got %#lx\n", hr);
1365 hr = CoRevokeClassObject(obj_cookie);
1366 ok(hr == S_OK, "got %#lx\n", hr);
1368 CoUninitialize();
1369 ExitProcess(0);
1372 static void test_delegated_methods(void)
1374 HANDLE process, stop_event, ready_event;
1375 IPSFactoryBuffer *ps;
1376 ITest1 *test_obj;
1377 DWORD ps_cookie;
1378 CLSID clsid;
1379 HRESULT hr;
1380 int ret;
1382 stop_event = CreateEventA(NULL, TRUE, FALSE, "wine_cstub_test_server_stop");
1383 ready_event = CreateEventA(NULL, TRUE, FALSE, "wine_cstub_test_server_ready");
1385 process = create_process("server");
1386 ok(!WaitForSingleObject(ready_event, 5000), "wait failed\n");
1388 hr = NdrDllGetClassObject(&CLSID_test_ps, &IID_IPSFactoryBuffer, (void **)&ps,
1389 &aProxyFileList, &CLSID_test_ps, &gPFactory);
1390 ok(hr == S_OK, "got %#lx\n", hr);
1392 hr = CoRegisterClassObject(&CLSID_test_ps, (IUnknown *)ps,
1393 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &ps_cookie);
1394 ok(hr == S_OK, "got %#lx\n", hr);
1396 hr = CoRegisterPSClsid(&IID_ITest1, &CLSID_test_ps);
1397 ok(hr == S_OK, "got %#lx\n", hr);
1399 hr = CoCreateInstance(&CLSID_test1, NULL, CLSCTX_LOCAL_SERVER, &IID_ITest1, (void **)&test_obj);
1400 ok(hr == S_OK, "got %#lx\n", hr);
1402 ret = ITest1_square(test_obj, 3);
1403 ok(ret == 9, "got %d\n", ret);
1405 hr = ITest1_GetClassID(test_obj, &clsid);
1406 ok(hr == S_OK, "got %#lx\n", hr);
1407 ok(IsEqualGUID(&clsid, &CLSID_test1), "got %s\n", wine_dbgstr_guid(&clsid));
1409 ITest1_Release(test_obj);
1411 SetEvent(stop_event);
1412 ok(!WaitForSingleObject(process, 1000), "wait failed\n");
1414 hr = CoRevokeClassObject(ps_cookie);
1415 ok(hr == S_OK, "got %#lx\n", hr);
1418 typedef struct tagChannelBufferRefCount
1420 IRpcChannelBuffer IRpcChannelBuffer_iface;
1421 LONG RefCount;
1422 } CChannelBufferRefCount;
1424 static CChannelBufferRefCount* impl_from_IRpcChannelBuffer(IRpcChannelBuffer* iface)
1426 return CONTAINING_RECORD(iface, CChannelBufferRefCount, IRpcChannelBuffer_iface);
1429 static HRESULT WINAPI test_chanbuf_refcount_chan_query_interface(IRpcChannelBuffer* pchan,
1430 REFIID iid,
1431 void** ppv)
1433 if (IsEqualGUID(&IID_IRpcChannelBuffer, iid))
1435 *ppv = pchan;
1436 IRpcChannelBuffer_AddRef(pchan);
1437 return S_OK;
1439 return E_NOINTERFACE;
1442 static ULONG WINAPI test_chanbuf_refcount_chan_add_ref(IRpcChannelBuffer* pchan)
1444 CChannelBufferRefCount* This = impl_from_IRpcChannelBuffer(pchan);
1445 return InterlockedIncrement(&This->RefCount);
1448 static ULONG WINAPI test_chanbuf_refcount_chan_release(IRpcChannelBuffer* pchan)
1450 CChannelBufferRefCount* This = impl_from_IRpcChannelBuffer(pchan);
1451 return InterlockedDecrement(&This->RefCount);
1454 static HRESULT WINAPI test_chanbuf_refcount_chan_get_buffer(IRpcChannelBuffer* pchan,
1455 RPCOLEMESSAGE* msg,
1456 REFIID iid)
1458 ok(0, "call to GetBuffer not expected\n");
1459 return E_NOTIMPL;
1462 static HRESULT WINAPI test_chanbuf_refcount_chan_send_receive(IRpcChannelBuffer* pchan,
1463 RPCOLEMESSAGE* pMessage,
1464 ULONG* pStatus)
1466 ok(0, "call to SendReceive not expected\n");
1467 return E_NOTIMPL;
1470 static HRESULT WINAPI test_chanbuf_refcount_chan_free_buffer(IRpcChannelBuffer* pchan,
1471 RPCOLEMESSAGE* pMessage)
1473 ok(0, "call to FreeBuffer not expected\n");
1474 return E_NOTIMPL;
1477 static HRESULT WINAPI test_chanbuf_refcount_chan_get_dest_ctx(IRpcChannelBuffer* pchan,
1478 DWORD* pdwDestContext,
1479 void** ppvDestContext)
1481 *pdwDestContext = MSHCTX_LOCAL;
1482 *ppvDestContext = NULL;
1483 return S_OK;
1486 static HRESULT WINAPI test_chanbuf_refcount_chan_is_connected(IRpcChannelBuffer* pchan)
1488 ok(0, "call to IsConnected not expected\n");
1489 return E_NOTIMPL;
1492 static IRpcChannelBufferVtbl test_chanbuf_refcount_test_rpc_chan_vtbl =
1494 test_chanbuf_refcount_chan_query_interface,
1495 test_chanbuf_refcount_chan_add_ref,
1496 test_chanbuf_refcount_chan_release,
1497 test_chanbuf_refcount_chan_get_buffer,
1498 test_chanbuf_refcount_chan_send_receive,
1499 test_chanbuf_refcount_chan_free_buffer,
1500 test_chanbuf_refcount_chan_get_dest_ctx,
1501 test_chanbuf_refcount_chan_is_connected
1504 static void test_ChannelBufferRefCount(IPSFactoryBuffer *ppsf)
1506 IRpcProxyBuffer* proxy_buffer = NULL;
1507 IUnknown* proxy_if1 = NULL;
1508 CChannelBufferRefCount test_chanbuf = {{&test_chanbuf_refcount_test_rpc_chan_vtbl}, 1};
1510 RPC_MESSAGE rpcMessage = {0};
1511 MIDL_STUB_MESSAGE stubMessage = {0};
1512 MIDL_STUB_DESC stubDesc = {0};
1513 ULONG refs;
1515 HRESULT hr = IPSFactoryBuffer_CreateProxy(ppsf, NULL, &IID_if1, &proxy_buffer, (void**)&proxy_if1);
1516 ok(hr == S_OK, "got %#lx\n", hr);
1518 ok(test_chanbuf.RefCount == 1, "got %ld\n", test_chanbuf.RefCount);
1519 hr = IRpcProxyBuffer_Connect(proxy_buffer, &test_chanbuf.IRpcChannelBuffer_iface);
1520 ok(hr == S_OK, "got %#lx\n", hr);
1521 /* proxy_buffer should have acquired its own refcount on test_chanbuf */
1522 ok(test_chanbuf.RefCount == 2, "got %ld\n", test_chanbuf.RefCount);
1524 /* which therefore survives releasing the initial one */
1525 refs = IRpcChannelBuffer_Release(&test_chanbuf.IRpcChannelBuffer_iface);
1526 ok(refs == 1, "got %ld\n", refs);
1528 NdrProxyInitialize(proxy_if1, &rpcMessage, &stubMessage, &stubDesc, 0);
1529 /* stubMessage should add its own refcount on test_chanbuf */
1530 ok(test_chanbuf.RefCount == 2, "got %ld\n", test_chanbuf.RefCount);
1531 ok(stubMessage.pRpcChannelBuffer != NULL, "NULL pRocChannelBuffer\n");
1533 /* stubMessage doesn't add its own refcounts on proxy_if1 or proxy_buffer,
1534 * so it's possible these are freed out from under it.
1535 * E.g. an event sink might unadvise upon receiving the event it was waiting for;
1536 * this unadvise could be reentrant to Invoke because SendReceive pumps STA messages.
1537 * The source would then erase that connection point entry and Release the proxy. */
1538 IRpcProxyBuffer_Disconnect(proxy_buffer);
1539 ok(test_chanbuf.RefCount == 1, "got %ld\n", test_chanbuf.RefCount);
1540 IRpcProxyBuffer_Release(proxy_buffer);
1541 refs = IUnknown_Release(proxy_if1);
1542 ok(refs == 0, "got %ld\n", refs);
1543 ok(test_chanbuf.RefCount == 1, "got %ld\n", test_chanbuf.RefCount);
1545 /* NdrProxyFreeBuffer must not dereference the now-freed proxy_if1,
1546 * yet should still free the remaining reference on test_chanbuf */
1547 NdrProxyFreeBuffer(proxy_if1, &stubMessage);
1548 ok(test_chanbuf.RefCount == 0, "got %ld\n", test_chanbuf.RefCount);
1549 ok(!stubMessage.pRpcChannelBuffer, "dangling pRpcChannelBuffer = %p\n", stubMessage.pRpcChannelBuffer);
1552 START_TEST( cstub )
1554 IPSFactoryBuffer *ppsf;
1555 int argc;
1556 char **argv;
1558 argc = winetest_get_mainargs( &argv );
1559 if (argc > 2 && !strcmp(argv[2], "server"))
1561 local_server_proc();
1562 return;
1565 OleInitialize(NULL);
1567 ppsf = test_NdrDllGetClassObject();
1568 test_NdrStubForwardingFunction();
1569 test_CreateProxy(ppsf);
1570 test_CreateStub(ppsf);
1571 test_Connect(ppsf);
1572 test_Disconnect(ppsf);
1573 test_Release(ppsf);
1574 test_delegating_Invoke(ppsf);
1575 test_NdrDllRegisterProxy();
1576 test_delegated_methods();
1577 test_ChannelBufferRefCount(ppsf);
1579 OleUninitialize();