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 #include "initguid.h"
33 #include <ole2.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 static CLSID CLSID_psfact = {0x1234567c, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
48 
49 static int my_alloc_called;
50 static int my_free_called;
51 
52 static void * CALLBACK my_alloc(SIZE_T size)
53 {
54     my_alloc_called++;
55     return NdrOleAllocate(size);
56 }
57 
58 static void CALLBACK my_free(void *ptr)
59 {
60     my_free_called++;
61     NdrOleFree(ptr);
62 }
63 
64 typedef struct _MIDL_PROC_FORMAT_STRING
65 {
66     short          Pad;
67     unsigned char  Format[ 2 ];
68 } MIDL_PROC_FORMAT_STRING;
69 
70 typedef struct _MIDL_TYPE_FORMAT_STRING
71 {
72     short          Pad;
73     unsigned char  Format[ 2 ];
74 } MIDL_TYPE_FORMAT_STRING;
75 
76 
77 static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =
78 {
79     0,
80     {
81         0, 0
82     }
83 };
84 
85 static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =
86 {
87     0,
88     {
89         0, 0
90     }
91 };
92 
93 static const MIDL_STUB_DESC Object_StubDesc =
94     {
95     NULL,
96     my_alloc,
97     my_free,
98     { 0 },
99     0,
100     0,
101     0,
102     0,
103     __MIDL_TypeFormatString.Format,
104     1, /* -error bounds_check flag */
105     0x20000, /* Ndr library version */
106     0,
107     0x50100a4, /* MIDL Version 5.1.164 */
108     0,
109     NULL,
110     0,  /* notify & notify_flag routine table */
111     1,  /* Flags */
112     0,  /* Reserved3 */
113     0,  /* Reserved4 */
114     0   /* Reserved5 */
115     };
116 
117 static HRESULT WINAPI if1_fn1_Proxy(void *This)
118 {
119     return S_OK;
120 }
121 
122 static void __RPC_STUB if1_fn1_Stub(
123     IRpcStubBuffer *This,
124     IRpcChannelBuffer *_pRpcChannelBuffer,
125     PRPC_MESSAGE _pRpcMessage,
126     DWORD *_pdwStubPhase)
127 {
128     trace("fn1 stub\n");
129 }
130 
131 static HRESULT WINAPI if1_fn2_Proxy(void *This)
132 {
133     return S_OK;
134 }
135 
136 static void __RPC_STUB if1_fn2_Stub(
137     IRpcStubBuffer *This,
138     IRpcChannelBuffer *_pRpcChannelBuffer,
139     PRPC_MESSAGE _pRpcMessage,
140     DWORD *_pdwStubPhase)
141 {
142     trace("fn2 stub\n");
143 }
144 
145 static CINTERFACE_PROXY_VTABLE(5) if1_proxy_vtbl =
146 {
147     { &IID_if1 },
148     {   IUnknown_QueryInterface_Proxy,
149         IUnknown_AddRef_Proxy,
150         IUnknown_Release_Proxy ,
151         if1_fn1_Proxy,
152         if1_fn2_Proxy
153     }
154 };
155 
156 
157 static const unsigned short if1_FormatStringOffsetTable[] =
158     {
159     0,
160     0
161     };
162 
163 static const MIDL_SERVER_INFO if1_server_info =
164     {
165     &Object_StubDesc,
166     0,
167     __MIDL_ProcFormatString.Format,
168     &if1_FormatStringOffsetTable[-3],
169     0,
170     0,
171     0,
172     0};
173 
174 
175 static const PRPC_STUB_FUNCTION if1_table[] =
176 {
177     if1_fn1_Stub,
178     if1_fn2_Stub
179 };
180 
181 static CInterfaceStubVtbl if1_stub_vtbl =
182 {
183     {
184         &IID_if1,
185         &if1_server_info,
186         5,
187         &if1_table[-3]
188     },
189     { CStdStubBuffer_METHODS }
190 };
191 
192 static CINTERFACE_PROXY_VTABLE(13) if2_proxy_vtbl =
193 {
194     { &IID_if2 },
195     {   IUnknown_QueryInterface_Proxy,
196         IUnknown_AddRef_Proxy,
197         IUnknown_Release_Proxy ,
198         0,
199         0,
200         0,
201         0,
202         0,
203         0,
204         0,
205         0,
206         0,
207         0
208     }
209 };
210 
211 static const unsigned short if2_FormatStringOffsetTable[] =
212     {
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     (unsigned short) -1,
223     0
224     };
225 
226 static const MIDL_SERVER_INFO if2_server_info =
227     {
228     &Object_StubDesc,
229     0,
230     __MIDL_ProcFormatString.Format,
231     &if2_FormatStringOffsetTable[-3],
232     0,
233     0,
234     0,
235     0};
236 
237 
238 static const PRPC_STUB_FUNCTION if2_table[] =
239 {
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     STUB_FORWARDING_FUNCTION
250 };
251 
252 static CInterfaceStubVtbl if2_stub_vtbl =
253 {
254     {
255         &IID_if2,
256         &if2_server_info,
257         13,
258         &if2_table[-3]
259     },
260     { CStdStubBuffer_DELEGATING_METHODS }
261 };
262 
263 static CINTERFACE_PROXY_VTABLE(5) if3_proxy_vtbl =
264 {
265     { &IID_if3 },
266     {   IUnknown_QueryInterface_Proxy,
267         IUnknown_AddRef_Proxy,
268         IUnknown_Release_Proxy ,
269         if1_fn1_Proxy,
270         0
271     }
272 };
273 
274 
275 static const unsigned short if3_FormatStringOffsetTable[] =
276     {
277     0,
278     0
279     };
280 
281 static const MIDL_SERVER_INFO if3_server_info =
282     {
283     &Object_StubDesc,
284     0,
285     __MIDL_ProcFormatString.Format,
286     &if3_FormatStringOffsetTable[-3],
287     0,
288     0,
289     0,
290     0};
291 
292 static CInterfaceStubVtbl if3_stub_vtbl =
293 {
294     {
295         &IID_if3,
296         &if3_server_info,
297         5,
298         &if1_table[-3]
299     },
300     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
301 };
302 
303 static CINTERFACE_PROXY_VTABLE(7) if4_proxy_vtbl =
304 {
305     { &IID_if4 },
306     {   IUnknown_QueryInterface_Proxy,
307         IUnknown_AddRef_Proxy,
308         IUnknown_Release_Proxy ,
309         0,
310         0,
311         0,
312         0
313     }
314 };
315 
316 static const unsigned short if4_FormatStringOffsetTable[] =
317     {
318     (unsigned short) -1,
319     (unsigned short) -1,
320     (unsigned short) -1,
321     (unsigned short) -1,
322     0
323     };
324 
325 static const MIDL_SERVER_INFO if4_server_info =
326     {
327     &Object_StubDesc,
328     0,
329     __MIDL_ProcFormatString.Format,
330     &if4_FormatStringOffsetTable[-3],
331     0,
332     0,
333     0,
334     0};
335 
336 static CInterfaceStubVtbl if4_stub_vtbl =
337 {
338     {
339         &IID_if4,
340         &if4_server_info,
341         7,
342         &if2_table[-3]
343     },
344     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
345 };
346 
347 static const CInterfaceProxyVtbl *cstub_ProxyVtblList[] =
348 {
349     (const CInterfaceProxyVtbl *) &if1_proxy_vtbl,
350     (const CInterfaceProxyVtbl *) &if2_proxy_vtbl,
351     (const CInterfaceProxyVtbl *) &if3_proxy_vtbl,
352     (const CInterfaceProxyVtbl *) &if4_proxy_vtbl,
353     NULL
354 };
355 
356 static const CInterfaceStubVtbl *cstub_StubVtblList[] =
357 {
358     &if1_stub_vtbl,
359     &if2_stub_vtbl,
360     &if3_stub_vtbl,
361     &if4_stub_vtbl,
362     NULL
363 };
364 
365 static PCInterfaceName const if_name_list[] =
366 {
367     "if1",
368     "if2",
369     "if3",
370     "if4",
371     NULL
372 };
373 
374 static const IID *base_iid_list[] =
375 {
376     NULL,
377     &IID_ITypeLib,
378     NULL,
379     &IID_IDispatch,
380     NULL
381 };
382 
383 #define cstub_CHECK_IID(n)     IID_GENERIC_CHECK_IID( cstub, pIID, n)
384 
385 static int __stdcall iid_lookup( const IID * pIID, int * pIndex )
386 {
387     IID_BS_LOOKUP_SETUP
388 
389     IID_BS_LOOKUP_INITIAL_TEST( cstub, 4, 4 )
390     IID_BS_LOOKUP_NEXT_TEST( cstub, 2 )
391     IID_BS_LOOKUP_NEXT_TEST( cstub, 1 )
392     IID_BS_LOOKUP_RETURN_RESULT( cstub, 4, *pIndex )
393 
394 }
395 
396 
397 static BOOL check_address(void *actual, void *expected)
398 {
399     static void *ole32_start = NULL;
400     static void *ole32_end = NULL;
401     static void *combase_start = NULL;
402     static void *combase_end = NULL;
403 
404     if (actual == expected)
405         return TRUE;
406 
407     /* On Win7, actual can be located inside ole32.dll */
408     if (ole32_start == NULL || ole32_end == NULL)
409     {
410         PIMAGE_NT_HEADERS nt_headers;
411         ole32_start = (void *) GetModuleHandleA("ole32.dll");
412         if (ole32_start == NULL)
413             return FALSE;
414         nt_headers = (PIMAGE_NT_HEADERS)((char *) ole32_start + ((PIMAGE_DOS_HEADER) ole32_start)->e_lfanew);
415         ole32_end = (void *)((char *) ole32_start + nt_headers->OptionalHeader.SizeOfImage);
416     }
417 
418     if (ole32_start <= actual && actual < ole32_end)
419         return TRUE;
420 
421     /* On Win8, actual can be located inside combase.dll */
422     if (combase_start == NULL || combase_end == NULL)
423     {
424         PIMAGE_NT_HEADERS nt_headers;
425         combase_start = (void *) GetModuleHandleA("combase.dll");
426         if (combase_start == NULL)
427             return FALSE;
428         nt_headers = (PIMAGE_NT_HEADERS)((char *) combase_start + ((PIMAGE_DOS_HEADER) combase_start)->e_lfanew);
429         combase_end = (void *)((char *) combase_start + nt_headers->OptionalHeader.SizeOfImage);
430     }
431 
432     return (combase_start <= actual && actual < combase_end);
433 }
434 
435 static const ExtendedProxyFileInfo my_proxy_file_info =
436 {
437     (const PCInterfaceProxyVtblList *) &cstub_ProxyVtblList,
438     (const PCInterfaceStubVtblList *) &cstub_StubVtblList,
439     (const PCInterfaceName *) &if_name_list,
440     (const IID **) &base_iid_list,
441     &iid_lookup,
442     4,
443     1,
444     NULL,
445     0,
446     0,
447     0
448 };
449 
450 static const ProxyFileInfo *proxy_file_list[] = {
451     &my_proxy_file_info,
452     NULL
453 };
454 
455 
456 static IPSFactoryBuffer *test_NdrDllGetClassObject(void)
457 {
458     HMODULE rpcrt4 = GetModuleHandleA("rpcrt4.dll");
459     IPSFactoryBuffer *ppsf = NULL;
460     const PCInterfaceProxyVtblList* proxy_vtbl;
461     const PCInterfaceStubVtblList* stub_vtbl;
462     const CLSID CLSID_Unknown = {0x45678, 0x1234, 0x6666, {0xff, 0x67, 0x45, 0x98, 0x76, 0x12, 0x34, 0x56}};
463     static const GUID * const interfaces[] = { &IID_if1, &IID_if2, &IID_if3, &IID_if4 };
464     UINT i;
465     HRESULT r;
466     HMODULE hmod = GetModuleHandleA("rpcrt4.dll");
467     void *CStd_QueryInterface = GetProcAddress(hmod, "CStdStubBuffer_QueryInterface");
468     void *CStd_AddRef = GetProcAddress(hmod, "CStdStubBuffer_AddRef");
469     void *CStd_Release = GetProcAddress(hmod, "NdrCStdStubBuffer_Release");
470     void *CStd_Connect = GetProcAddress(hmod, "CStdStubBuffer_Connect");
471     void *CStd_Disconnect = GetProcAddress(hmod, "CStdStubBuffer_Disconnect");
472     void *CStd_Invoke = GetProcAddress(hmod, "CStdStubBuffer_Invoke");
473     void *CStd_IsIIDSupported = GetProcAddress(hmod, "CStdStubBuffer_IsIIDSupported");
474     void *CStd_CountRefs = GetProcAddress(hmod, "CStdStubBuffer_CountRefs");
475     void *CStd_DebugServerQueryInterface = GetProcAddress(hmod, "CStdStubBuffer_DebugServerQueryInterface");
476     void *CStd_DebugServerRelease = GetProcAddress(hmod, "CStdStubBuffer_DebugServerRelease");
477 
478     r = NdrDllGetClassObject(&CLSID_Unknown, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
479                              &CLSID_psfact, &PSFactoryBuffer);
480     ok(r == CLASS_E_CLASSNOTAVAILABLE, "NdrDllGetClassObject with unknown clsid should have returned CLASS_E_CLASSNOTAVAILABLE instead of 0x%x\n", r);
481     ok(ppsf == NULL, "NdrDllGetClassObject should have set ppsf to NULL on failure\n");
482 
483     r = NdrDllGetClassObject(&CLSID_psfact, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
484                              &CLSID_psfact, &PSFactoryBuffer);
485 
486     ok(r == S_OK, "ret %08x\n", r);
487     ok(ppsf != NULL, "ppsf == NULL\n");
488 
489     proxy_vtbl = PSFactoryBuffer.pProxyFileList[0]->pProxyVtblList;
490     stub_vtbl = PSFactoryBuffer.pProxyFileList[0]->pStubVtblList;
491     ok(PSFactoryBuffer.pProxyFileList == proxy_file_list, "pfl not the same\n");
492     ok(proxy_vtbl == (PCInterfaceProxyVtblList *) &cstub_ProxyVtblList, "proxy vtbllist not the same\n");
493     ok(stub_vtbl == (PCInterfaceStubVtblList *) &cstub_StubVtblList, "stub vtbllist not the same\n");
494 
495     /* if1 is non-delegating, if2 is delegating, if3 is non-delegating
496        but I've zero'ed the vtbl entries, similarly if4 is delegating
497        with zero'ed vtbl entries */
498 
499 #define VTBL_TEST_NOT_CHANGE_TO(name, i)                                  \
500     ok(stub_vtbl[i]->Vtbl.name != CStd_##name, #name "vtbl %d updated %p %p\n", \
501        i, stub_vtbl[i]->Vtbl.name, CStd_##name )
502 #define VTBL_TEST_CHANGE_TO(name, i)                                  \
503     ok(check_address(stub_vtbl[i]->Vtbl.name, CStd_##name), #name "vtbl %d not updated %p %p\n", \
504        i, stub_vtbl[i]->Vtbl.name, CStd_##name )
505 #define VTBL_TEST_ZERO(name, i)                                  \
506     ok(stub_vtbl[i]->Vtbl.name == NULL, #name "vtbl %d not null %p\n", \
507        i, stub_vtbl[i]->Vtbl.name )
508 
509     VTBL_TEST_NOT_CHANGE_TO(QueryInterface, 0);
510     VTBL_TEST_NOT_CHANGE_TO(AddRef, 0);
511     VTBL_TEST_NOT_CHANGE_TO(Release, 0);
512     VTBL_TEST_NOT_CHANGE_TO(Connect, 0);
513     VTBL_TEST_NOT_CHANGE_TO(Disconnect, 0);
514     VTBL_TEST_NOT_CHANGE_TO(Invoke, 0);
515     VTBL_TEST_NOT_CHANGE_TO(IsIIDSupported, 0);
516     VTBL_TEST_NOT_CHANGE_TO(CountRefs, 0);
517     VTBL_TEST_NOT_CHANGE_TO(DebugServerQueryInterface, 0);
518     VTBL_TEST_NOT_CHANGE_TO(DebugServerRelease, 0);
519 
520     VTBL_TEST_CHANGE_TO(QueryInterface, 1);
521     VTBL_TEST_CHANGE_TO(AddRef, 1);
522     VTBL_TEST_NOT_CHANGE_TO(Release, 1);
523     VTBL_TEST_NOT_CHANGE_TO(Connect, 1);
524     VTBL_TEST_NOT_CHANGE_TO(Disconnect, 1);
525     VTBL_TEST_CHANGE_TO(Invoke, 1);
526     VTBL_TEST_CHANGE_TO(IsIIDSupported, 1);
527     VTBL_TEST_NOT_CHANGE_TO(CountRefs, 1);
528     VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 1);
529     VTBL_TEST_CHANGE_TO(DebugServerRelease, 1);
530 
531     VTBL_TEST_CHANGE_TO(QueryInterface, 2);
532     VTBL_TEST_CHANGE_TO(AddRef, 2);
533     VTBL_TEST_ZERO(Release, 2);
534     VTBL_TEST_CHANGE_TO(Connect, 2);
535     VTBL_TEST_CHANGE_TO(Disconnect, 2);
536     VTBL_TEST_CHANGE_TO(Invoke, 2);
537     VTBL_TEST_CHANGE_TO(IsIIDSupported, 2);
538     VTBL_TEST_CHANGE_TO(CountRefs, 2);
539     VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 2);
540     VTBL_TEST_CHANGE_TO(DebugServerRelease, 2);
541 
542     VTBL_TEST_CHANGE_TO(QueryInterface, 3);
543     VTBL_TEST_CHANGE_TO(AddRef, 3);
544     VTBL_TEST_ZERO(Release, 3);
545     VTBL_TEST_NOT_CHANGE_TO(Connect, 3);
546     VTBL_TEST_NOT_CHANGE_TO(Disconnect, 3);
547     VTBL_TEST_CHANGE_TO(Invoke, 3);
548     VTBL_TEST_CHANGE_TO(IsIIDSupported, 3);
549     VTBL_TEST_NOT_CHANGE_TO(CountRefs, 3);
550     VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 3);
551     VTBL_TEST_CHANGE_TO(DebugServerRelease, 3);
552 
553 #define VTBL_PROXY_TEST(i,num,ptr) \
554     ok( check_address(proxy_vtbl[i]->Vtbl[num], (ptr)), "wrong proxy %u func %u %p/%p\n", \
555         (i), (num), proxy_vtbl[i]->Vtbl[num], (ptr) )
556 #define VTBL_PROXY_TEST_NOT_ZERO(i,num) \
557     ok( proxy_vtbl[i]->Vtbl[num] != NULL, "wrong proxy %u func %u is NULL\n", (i), (num))
558 
559     VTBL_PROXY_TEST(0, 0, IUnknown_QueryInterface_Proxy);
560     VTBL_PROXY_TEST(0, 1, IUnknown_AddRef_Proxy);
561     VTBL_PROXY_TEST(0, 2, IUnknown_Release_Proxy);
562     VTBL_PROXY_TEST(0, 3, if1_fn1_Proxy);
563     VTBL_PROXY_TEST(0, 4, if1_fn2_Proxy);
564 
565     VTBL_PROXY_TEST(1, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy"));
566     VTBL_PROXY_TEST(1, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy"));
567     VTBL_PROXY_TEST(1, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy"));
568     VTBL_PROXY_TEST_NOT_ZERO(1, 3);
569     VTBL_PROXY_TEST_NOT_ZERO(1, 4);
570     VTBL_PROXY_TEST_NOT_ZERO(1, 5);
571     VTBL_PROXY_TEST_NOT_ZERO(1, 6);
572     VTBL_PROXY_TEST_NOT_ZERO(1, 7);
573     VTBL_PROXY_TEST_NOT_ZERO(1, 8);
574     VTBL_PROXY_TEST_NOT_ZERO(1, 9);
575     VTBL_PROXY_TEST_NOT_ZERO(1, 10);
576     VTBL_PROXY_TEST_NOT_ZERO(1, 11);
577     VTBL_PROXY_TEST_NOT_ZERO(1, 12);
578 
579     VTBL_PROXY_TEST(2, 0, IUnknown_QueryInterface_Proxy);
580     VTBL_PROXY_TEST(2, 1, IUnknown_AddRef_Proxy);
581     VTBL_PROXY_TEST(2, 2, IUnknown_Release_Proxy);
582     VTBL_PROXY_TEST(2, 3, if1_fn1_Proxy);
583     todo_wine VTBL_PROXY_TEST_NOT_ZERO(2, 4);
584 
585     VTBL_PROXY_TEST(3, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy"));
586     VTBL_PROXY_TEST(3, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy"));
587     VTBL_PROXY_TEST(3, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy"));
588     VTBL_PROXY_TEST_NOT_ZERO(3, 3);
589     VTBL_PROXY_TEST_NOT_ZERO(3, 4);
590     VTBL_PROXY_TEST_NOT_ZERO(3, 5);
591     VTBL_PROXY_TEST_NOT_ZERO(3, 6);
592 
593 #undef VTBL_TEST_NOT_CHANGE_TO
594 #undef VTBL_TEST_CHANGE_TO
595 #undef VTBL_TEST_ZERO
596 #undef VTBL_PROXY_TEST
597 #undef VTBL_PROXY_TEST_NOT_ZERO
598 
599     for (i = 0; i < sizeof(interfaces)/sizeof(interfaces[0]); i++)
600         ok( proxy_vtbl[i]->header.piid == interfaces[i],
601             "wrong proxy %u iid %p/%p\n", i, proxy_vtbl[i]->header.piid, interfaces[i] );
602 
603     ok(PSFactoryBuffer.RefCount == 1, "ref count %d\n", PSFactoryBuffer.RefCount);
604     IPSFactoryBuffer_Release(ppsf);
605 
606     /* One can also search by IID */
607     r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
608                              &CLSID_psfact, &PSFactoryBuffer);
609     ok(r == S_OK, "ret %08x\n", r);
610     ok(ppsf != NULL, "ppsf == NULL\n");
611     IPSFactoryBuffer_Release(ppsf);
612 
613     r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
614                              NULL, &PSFactoryBuffer);
615     ok(r == S_OK, "ret %08x\n", r);
616     ok(ppsf != NULL, "ppsf == NULL\n");
617     IPSFactoryBuffer_Release(ppsf);
618 
619     /* but only if the PS factory implements it */
620     r = NdrDllGetClassObject(&IID_IDispatch, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
621                              &CLSID_psfact, &PSFactoryBuffer);
622     ok(r == CLASS_E_CLASSNOTAVAILABLE, "ret %08x\n", r);
623 
624     /* Create it again to return */
625     r = NdrDllGetClassObject(&CLSID_psfact, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list,
626                              &CLSID_psfact, &PSFactoryBuffer);
627     ok(r == S_OK, "ret %08x\n", r);
628     ok(ppsf != NULL, "ppsf == NULL\n");
629 
630     /* Because this PS factory is not loaded as a dll in the normal way, Windows 8 / 10
631        get confused and will crash when one of the proxies for the delegated ifaces is created.
632        Registering the ifaces fixes this (in fact calling CoRegisterPSClsid() with any IID / CLSID is enough). */
633 
634     r = CoRegisterPSClsid(&IID_if1, &CLSID_psfact);
635     ok(r == S_OK, "ret %08x\n", r);
636     r = CoRegisterPSClsid(&IID_if2, &CLSID_psfact);
637     ok(r == S_OK, "ret %08x\n", r);
638     r = CoRegisterPSClsid(&IID_if3, &CLSID_psfact);
639     ok(r == S_OK, "ret %08x\n", r);
640     r = CoRegisterPSClsid(&IID_if4, &CLSID_psfact);
641     ok(r == S_OK, "ret %08x\n", r);
642 
643     return ppsf;
644 }
645 
646 static int base_buffer_invoke_called;
647 static HRESULT WINAPI base_buffer_Invoke(IRpcStubBuffer *This, RPCOLEMESSAGE *msg, IRpcChannelBuffer *channel)
648 {
649     base_buffer_invoke_called++;
650     ok(msg == (RPCOLEMESSAGE*)0xcafebabe, "msg ptr changed\n");
651     ok(channel == (IRpcChannelBuffer*)0xdeadbeef, "channel ptr changed\n");
652     return S_OK; /* returning any failure here results in an exception */
653 }
654 
655 static IRpcStubBufferVtbl base_buffer_vtbl = {
656     (void*)0xcafebab0,
657     (void*)0xcafebab1,
658     (void*)0xcafebab2,
659     (void*)0xcafebab3,
660     (void*)0xcafebab4,
661     base_buffer_Invoke,
662     (void*)0xcafebab6,
663     (void*)0xcafebab7,
664     (void*)0xcafebab8,
665     (void*)0xcafebab9
666 };
667 
668 static void test_NdrStubForwardingFunction(void)
669 {
670     void *This[5];
671     void *real_this;
672     IRpcChannelBuffer *channel = (IRpcChannelBuffer*)0xdeadbeef;
673     RPC_MESSAGE *msg = (RPC_MESSAGE*)0xcafebabe;
674     DWORD *phase = (DWORD*)0x12345678;
675     IRpcStubBufferVtbl *base_buffer_vtbl_ptr = &base_buffer_vtbl;
676     IRpcStubBuffer *base_stub_buffer = (IRpcStubBuffer*)&base_buffer_vtbl_ptr;
677 
678     memset(This, 0xcc, sizeof(This));
679     This[0] = base_stub_buffer;
680     real_this = &This[1];
681 
682     NdrStubForwardingFunction( real_this, channel, msg, phase );
683     ok(base_buffer_invoke_called == 1, "base_buffer_invoke called %d times\n", base_buffer_invoke_called);
684 
685 }
686 
687 static IRpcStubBuffer *create_stub(IPSFactoryBuffer *ppsf, REFIID iid, IUnknown *obj, HRESULT expected_result)
688 {
689     IRpcStubBuffer *pstub = NULL;
690     HRESULT r;
691 
692     r = IPSFactoryBuffer_CreateStub(ppsf, iid, obj, &pstub);
693     ok(r == expected_result, "CreateStub returned %08x expected %08x\n", r, expected_result);
694     return pstub;
695 }
696 
697 static HRESULT WINAPI create_stub_test_QI(IUnknown *This, REFIID iid, void **ppv)
698 {
699     ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
700     *ppv = (void*)0xdeadbeef;
701     return S_OK;
702 }
703 
704 static IUnknownVtbl create_stub_test_vtbl =
705 {
706     create_stub_test_QI,
707     NULL,
708     NULL
709 };
710 
711 static HRESULT WINAPI create_stub_test_fail_QI(IUnknown *This, REFIID iid, void **ppv)
712 {
713     ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
714     *ppv = NULL;
715     return E_NOINTERFACE;
716 }
717 
718 static IUnknownVtbl create_stub_test_fail_vtbl =
719 {
720     create_stub_test_fail_QI,
721     NULL,
722     NULL
723 };
724 
725 struct dummy_unknown
726 {
727     IUnknown IUnknown_iface;
728     LONG ref;
729 };
730 
731 static inline struct dummy_unknown *impl_from_IUnknown(IUnknown *iface)
732 {
733     return CONTAINING_RECORD(iface, struct dummy_unknown, IUnknown_iface);
734 }
735 
736 static HRESULT WINAPI dummy_QueryInterface(IUnknown *This, REFIID iid, void **ppv)
737 {
738     *ppv = NULL;
739     return E_NOINTERFACE;
740 }
741 
742 static ULONG WINAPI dummy_AddRef(LPUNKNOWN iface)
743 {
744     struct dummy_unknown *this = impl_from_IUnknown(iface);
745     return InterlockedIncrement( &this->ref );
746 }
747 
748 static ULONG WINAPI dummy_Release(LPUNKNOWN iface)
749 {
750     struct dummy_unknown *this = impl_from_IUnknown(iface);
751     return InterlockedDecrement( &this->ref );
752 }
753 
754 static IUnknownVtbl dummy_unknown_vtbl =
755 {
756     dummy_QueryInterface,
757     dummy_AddRef,
758     dummy_Release
759 };
760 static struct dummy_unknown dummy_unknown = { { &dummy_unknown_vtbl }, 0 };
761 
762 static void create_proxy_test( IPSFactoryBuffer *ppsf, REFIID iid, const void *expected_vtbl )
763 {
764     IRpcProxyBuffer *proxy = NULL;
765     IUnknown *iface = NULL;
766     HRESULT r;
767     ULONG count;
768 
769     r = IPSFactoryBuffer_CreateProxy(ppsf, NULL, iid, &proxy, (void **)&iface);
770     ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r );
771     ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
772     count = IUnknown_Release( iface );
773     ok( count == 1, "wrong refcount %u\n", count );
774     count = IRpcProxyBuffer_Release( proxy );
775     ok( count == 0, "wrong refcount %u\n", count );
776 
777     dummy_unknown.ref = 4;
778     r = IPSFactoryBuffer_CreateProxy(ppsf, &dummy_unknown.IUnknown_iface, iid, &proxy,
779             (void **)&iface);
780     ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r );
781     ok( dummy_unknown.ref == 5, "wrong refcount %u\n", dummy_unknown.ref );
782     ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl );
783     count = IUnknown_Release( iface );
784     ok( count == 4, "wrong refcount %u\n", count );
785     ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref );
786     count = IRpcProxyBuffer_Release( proxy );
787     ok( count == 0, "wrong refcount %u\n", count );
788     ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref );
789 }
790 
791 static void test_CreateProxy( IPSFactoryBuffer *ppsf )
792 {
793     create_proxy_test( ppsf, &IID_if1, if1_proxy_vtbl.Vtbl );
794     create_proxy_test( ppsf, &IID_if2, if2_proxy_vtbl.Vtbl );
795     create_proxy_test( ppsf, &IID_if3, if3_proxy_vtbl.Vtbl );
796     create_proxy_test( ppsf, &IID_if4, if4_proxy_vtbl.Vtbl );
797 }
798 
799 static void test_CreateStub(IPSFactoryBuffer *ppsf)
800 {
801     IUnknownVtbl *vtbl = &create_stub_test_vtbl;
802     IUnknown *obj = (IUnknown*)&vtbl;
803     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
804     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
805     const CInterfaceStubHeader *header = &CONTAINING_RECORD(cstd_stub->lpVtbl, const CInterfaceStubVtbl, Vtbl)->header;
806 
807     ok(IsEqualIID(header->piid, &IID_if1), "header iid differs\n");
808     ok(cstd_stub->RefCount == 1, "ref count %d\n", cstd_stub->RefCount);
809     /* 0xdeadbeef returned from create_stub_test_QI */
810     ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
811     ok(cstd_stub->pPSFactory != NULL, "pPSFactory was NULL\n");
812     cstd_stub->pvServerObject = NULL;
813     IRpcStubBuffer_Release(pstub);
814 
815     vtbl = &create_stub_test_fail_vtbl;
816     pstub = create_stub(ppsf, &IID_if1, obj, E_NOINTERFACE);
817     ok(pstub == S_OK, "create_stub failed: %u\n", GetLastError());
818 
819 }
820 
821 static HRESULT WINAPI connect_test_orig_QI(IUnknown *This, REFIID iid, void **ppv)
822 {
823     ok(IsEqualIID(iid, &IID_if1) ||
824        IsEqualIID(iid, &IID_if2), "incorrect iid\n");
825     *ppv = (void*)This;
826     return S_OK;
827 }
828 
829 static int connect_test_orig_release_called;
830 static ULONG WINAPI connect_test_orig_release(IUnknown *This)
831 {
832     connect_test_orig_release_called++;
833     return 0;
834 }
835 
836 static IUnknownVtbl connect_test_orig_vtbl =
837 {
838     connect_test_orig_QI,
839     NULL,
840     connect_test_orig_release
841 };
842 
843 static HRESULT WINAPI connect_test_new_QI(IUnknown *This, REFIID iid, void **ppv)
844 {
845     ok(IsEqualIID(iid, &IID_if1) ||
846        IsEqualIID(iid, &IID_if2), "incorrect iid\n");
847     *ppv = (void*)0xcafebabe;
848     return S_OK;
849 }
850 
851 static IUnknownVtbl connect_test_new_vtbl =
852 {
853     connect_test_new_QI,
854     NULL,
855     NULL
856 };
857 
858 static HRESULT WINAPI connect_test_new_fail_QI(IUnknown *This, REFIID iid, void **ppv)
859 {
860     ok(IsEqualIID(iid, &IID_if1), "incorrect iid\n");
861     *ppv = (void*)0xdeadbeef;
862     return E_NOINTERFACE;
863 }
864 
865 static IUnknownVtbl connect_test_new_fail_vtbl =
866 {
867     connect_test_new_fail_QI,
868     NULL,
869     NULL
870 };
871 
872 static int connect_test_base_Connect_called;
873 static HRESULT WINAPI connect_test_base_Connect(IRpcStubBuffer *pstub, IUnknown *obj)
874 {
875     connect_test_base_Connect_called++;
876     ok(*(void**)obj == (void*)0xbeefcafe, "unexpected obj %p\n", obj);
877     return S_OK;
878 }
879 
880 static IRpcStubBufferVtbl connect_test_base_stub_buffer_vtbl =
881 {
882     (void*)0xcafebab0,
883     (void*)0xcafebab1,
884     (void*)0xcafebab2,
885     connect_test_base_Connect,
886     (void*)0xcafebab4,
887     (void*)0xcafebab5,
888     (void*)0xcafebab6,
889     (void*)0xcafebab7,
890     (void*)0xcafebab8,
891     (void*)0xcafebab9
892 };
893 
894 static void test_Connect(IPSFactoryBuffer *ppsf)
895 {
896     IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
897     IUnknownVtbl *new_vtbl = &connect_test_new_vtbl;
898     IUnknownVtbl *new_fail_vtbl = &connect_test_new_fail_vtbl;
899     IUnknown *obj = (IUnknown*)&orig_vtbl;
900     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
901     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
902     IRpcStubBufferVtbl *base_stub_buf_vtbl = &connect_test_base_stub_buffer_vtbl;
903     HRESULT r;
904 
905     obj = (IUnknown*)&new_vtbl;
906     r = IRpcStubBuffer_Connect(pstub, obj);
907     ok(r == S_OK, "r %08x\n", r);
908     ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
909     ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
910 
911     cstd_stub->pvServerObject = (IUnknown*)&orig_vtbl;
912     obj = (IUnknown*)&new_fail_vtbl;
913     r = IRpcStubBuffer_Connect(pstub, obj);
914     ok(r == E_NOINTERFACE, "r %08x\n", r);
915     ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject);
916     ok(connect_test_orig_release_called == 2, "release called %d\n", connect_test_orig_release_called);
917 
918     /* Now use a delegated stub.
919 
920        We know from the NdrStubForwardFunction test that
921        (void**)pstub-1 is the base interface stub buffer.  This shows
922        that (void**)pstub-2 contains the address of a vtable that gets
923        passed to the base interface's Connect method.  Note that
924        (void**)pstub-2 itself gets passed to Connect and not
925        *((void**)pstub-2), so it should contain the vtable ptr and not
926        an interface ptr. */
927 
928     obj = (IUnknown*)&orig_vtbl;
929     pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
930     *((void**)pstub-1) = &base_stub_buf_vtbl;
931     *((void**)pstub-2) = (void*)0xbeefcafe;
932 
933     obj = (IUnknown*)&new_vtbl;
934     r = IRpcStubBuffer_Connect(pstub, obj);
935     ok(r == S_OK, "r %08x\n", r);
936     ok(connect_test_base_Connect_called == 1, "connect_test_bsae_Connect called %d times\n",
937        connect_test_base_Connect_called);
938     ok(connect_test_orig_release_called == 3, "release called %d\n", connect_test_orig_release_called);
939     cstd_stub = (CStdStubBuffer*)pstub;
940     ok(cstd_stub->pvServerObject == (void*)0xcafebabe, "pvServerObject %p\n", cstd_stub->pvServerObject);
941 }
942 
943 static void test_Disconnect(IPSFactoryBuffer *ppsf)
944 {
945     IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
946     IUnknown *obj = (IUnknown*)&orig_vtbl;
947     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
948     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
949 
950     connect_test_orig_release_called = 0;
951     IRpcStubBuffer_Disconnect(pstub);
952     ok(connect_test_orig_release_called == 1, "release called %d\n", connect_test_orig_release_called);
953     ok(cstd_stub->pvServerObject == NULL, "pvServerObject %p\n", cstd_stub->pvServerObject);
954     IRpcStubBuffer_Release(pstub);
955 }
956 
957 
958 static int release_test_psfacbuf_release_called;
959 static ULONG WINAPI release_test_pretend_psfacbuf_release(IUnknown *pUnk)
960 {
961     release_test_psfacbuf_release_called++;
962     return 1;
963 }
964 
965 static IUnknownVtbl release_test_pretend_psfacbuf_vtbl =
966 {
967     NULL,
968     NULL,
969     release_test_pretend_psfacbuf_release
970 };
971 
972 static void test_Release(IPSFactoryBuffer *ppsf)
973 {
974     LONG facbuf_refs;
975     IUnknownVtbl *orig_vtbl = &connect_test_orig_vtbl;
976     IUnknown *obj = (IUnknown*)&orig_vtbl;
977     IUnknownVtbl *pretend_psfacbuf_vtbl = &release_test_pretend_psfacbuf_vtbl;
978     IUnknown *pretend_psfacbuf = (IUnknown *)&pretend_psfacbuf_vtbl;
979     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
980     CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub;
981 
982     facbuf_refs = PSFactoryBuffer.RefCount;
983 
984     /* This shows that NdrCStdStubBuffer_Release doesn't call Disconnect */
985     ok(cstd_stub->RefCount == 1, "ref count %d\n", cstd_stub->RefCount);
986     connect_test_orig_release_called = 0;
987     IRpcStubBuffer_Release(pstub);
988 todo_wine {
989     ok(connect_test_orig_release_called == 0, "release called %d\n", connect_test_orig_release_called);
990 }
991     ok(PSFactoryBuffer.RefCount == facbuf_refs - 1, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
992 
993     /* This shows that NdrCStdStubBuffer_Release calls Release on its 2nd arg, rather than on This->pPSFactory
994        (which are usually the same and indeed it's odd that _Release requires this 2nd arg). */
995     pstub = create_stub(ppsf, &IID_if1, obj, S_OK);
996     ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
997     NdrCStdStubBuffer_Release(pstub, (IPSFactoryBuffer*)pretend_psfacbuf);
998     ok(release_test_psfacbuf_release_called == 1, "pretend_psfacbuf_release called %d\n", release_test_psfacbuf_release_called);
999     ok(PSFactoryBuffer.RefCount == facbuf_refs, "factory buffer refs %d orig %d\n", PSFactoryBuffer.RefCount, facbuf_refs);
1000 }
1001 
1002 static HRESULT WINAPI delegating_invoke_test_QI(ITypeLib *pUnk, REFIID iid, void** ppv)
1003 {
1004 
1005     *ppv = pUnk;
1006     return S_OK;
1007 }
1008 
1009 static ULONG WINAPI delegating_invoke_test_addref(ITypeLib *pUnk)
1010 {
1011     return 1;
1012 }
1013 
1014 static ULONG WINAPI delegating_invoke_test_release(ITypeLib *pUnk)
1015 {
1016     return 1;
1017 }
1018 
1019 static UINT WINAPI delegating_invoke_test_get_type_info_count(ITypeLib *pUnk)
1020 {
1021     return 0xabcdef;
1022 }
1023 
1024 static ITypeLibVtbl delegating_invoke_test_obj_vtbl =
1025 {
1026     delegating_invoke_test_QI,
1027     delegating_invoke_test_addref,
1028     delegating_invoke_test_release,
1029     delegating_invoke_test_get_type_info_count,
1030     NULL,
1031     NULL,
1032     NULL,
1033     NULL,
1034     NULL,
1035     NULL,
1036     NULL,
1037     NULL,
1038     NULL
1039 };
1040 
1041 static HRESULT WINAPI delegating_invoke_chan_query_interface(IRpcChannelBuffer *pchan,
1042                                                              REFIID iid,
1043                                                              void **ppv)
1044 {
1045     ok(0, "call to QueryInterface not expected\n");
1046     return E_NOINTERFACE;
1047 }
1048 
1049 static ULONG WINAPI delegating_invoke_chan_add_ref(IRpcChannelBuffer *pchan)
1050 {
1051     return 2;
1052 }
1053 
1054 static ULONG WINAPI delegating_invoke_chan_release(IRpcChannelBuffer *pchan)
1055 {
1056     return 1;
1057 }
1058 
1059 static HRESULT WINAPI delegating_invoke_chan_get_buffer(IRpcChannelBuffer *pchan,
1060                                                         RPCOLEMESSAGE *msg,
1061                                                         REFIID iid)
1062 {
1063     msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->cbBuffer);
1064     return S_OK;
1065 }
1066 
1067 static HRESULT WINAPI delegating_invoke_chan_send_receive(IRpcChannelBuffer *pchan,
1068                                                           RPCOLEMESSAGE *pMessage,
1069                                                           ULONG *pStatus)
1070 {
1071     ok(0, "call to SendReceive not expected\n");
1072     return E_NOTIMPL;
1073 }
1074 
1075 static HRESULT WINAPI delegating_invoke_chan_free_buffer(IRpcChannelBuffer *pchan,
1076                                                          RPCOLEMESSAGE *pMessage)
1077 {
1078     ok(0, "call to FreeBuffer not expected\n");
1079     return E_NOTIMPL;
1080 }
1081 
1082 static HRESULT WINAPI delegating_invoke_chan_get_dest_ctx(IRpcChannelBuffer *pchan,
1083                                                           DWORD *pdwDestContext,
1084                                                           void **ppvDestContext)
1085 {
1086     *pdwDestContext = MSHCTX_LOCAL;
1087     *ppvDestContext = NULL;
1088     return S_OK;
1089 }
1090 
1091 static HRESULT WINAPI delegating_invoke_chan_is_connected(IRpcChannelBuffer *pchan)
1092 {
1093     ok(0, "call to IsConnected not expected\n");
1094     return E_NOTIMPL;
1095 }
1096 
1097 static IRpcChannelBufferVtbl delegating_invoke_test_rpc_chan_vtbl =
1098 {
1099     delegating_invoke_chan_query_interface,
1100     delegating_invoke_chan_add_ref,
1101     delegating_invoke_chan_release,
1102     delegating_invoke_chan_get_buffer,
1103     delegating_invoke_chan_send_receive,
1104     delegating_invoke_chan_free_buffer,
1105     delegating_invoke_chan_get_dest_ctx,
1106     delegating_invoke_chan_is_connected
1107 };
1108 
1109 static void test_delegating_Invoke(IPSFactoryBuffer *ppsf)
1110 {
1111     ITypeLibVtbl *obj_vtbl = &delegating_invoke_test_obj_vtbl;
1112     IUnknown *obj = (IUnknown*)&obj_vtbl;
1113     IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if2, obj, S_OK);
1114     IRpcChannelBufferVtbl *pchan_vtbl = &delegating_invoke_test_rpc_chan_vtbl;
1115     IRpcChannelBuffer *pchan = (IRpcChannelBuffer *)&pchan_vtbl;
1116     HRESULT r = E_FAIL;
1117     RPCOLEMESSAGE msg;
1118 
1119     memset(&msg, 0, sizeof(msg));
1120     msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
1121     msg.iMethod = 3;
1122     r = IRpcStubBuffer_Invoke(pstub, &msg, pchan);
1123     ok(r == S_OK, "ret %08x\n", r);
1124     if(r == S_OK)
1125     {
1126         ok(*(DWORD*)msg.Buffer == 0xabcdef, "buf[0] %08x\n", *(DWORD*)msg.Buffer);
1127         ok(*((DWORD*)msg.Buffer + 1) == S_OK, "buf[1] %08x\n", *((DWORD*)msg.Buffer + 1));
1128     }
1129     /* free the buffer allocated by delegating_invoke_chan_get_buffer */
1130     HeapFree(GetProcessHeap(), 0, msg.Buffer);
1131     IRpcStubBuffer_Release(pstub);
1132 }
1133 static const CInterfaceProxyVtbl *cstub_ProxyVtblList2[] =
1134 {
1135     NULL
1136 };
1137 
1138 static const CInterfaceStubVtbl *cstub_StubVtblList2[] =
1139 {
1140     NULL
1141 };
1142 
1143 static PCInterfaceName const if_name_list2[] =
1144 {
1145     NULL
1146 };
1147 
1148 static const IID *base_iid_list2[] =
1149 {
1150     NULL,
1151 };
1152 
1153 static const ExtendedProxyFileInfo my_proxy_file_info2 =
1154 {
1155     (const PCInterfaceProxyVtblList *) &cstub_ProxyVtblList2,
1156     (const PCInterfaceStubVtblList *) &cstub_StubVtblList2,
1157     (const PCInterfaceName *) &if_name_list2,
1158     (const IID **) &base_iid_list2,
1159     &iid_lookup,
1160     0,
1161     1,
1162     NULL,
1163     0,
1164     0,
1165     0
1166 };
1167 
1168 static const ProxyFileInfo *proxy_file_list2[] = {
1169     &my_proxy_file_info2,
1170     NULL
1171 };
1172 
1173 static void test_NdrDllRegisterProxy( void )
1174 {
1175     HRESULT res;
1176     const ExtendedProxyFileInfo *pf;
1177     HMODULE hmod = GetModuleHandleA(NULL);
1178 
1179 
1180     res = NdrDllRegisterProxy(NULL, NULL, NULL);
1181     ok(res == E_HANDLE, "Incorrect return code %x\n",res);
1182     pf = NULL;
1183     res = NdrDllRegisterProxy(hmod, &pf, NULL);
1184     ok(res == E_NOINTERFACE, "Incorrect return code %x\n",res);
1185     res = NdrDllRegisterProxy(hmod, proxy_file_list2, NULL);
1186     ok(res == E_NOINTERFACE, "Incorrect return code %x\n",res);
1187     /* This fails on Vista and Windows 7 due to permissions */
1188     res = NdrDllRegisterProxy(hmod, proxy_file_list, NULL);
1189     ok(res == S_OK || res == E_ACCESSDENIED, "NdrDllRegisterProxy failed %x\n",res);
1190     if (res == S_OK)
1191     {
1192         res = NdrDllUnregisterProxy(hmod,proxy_file_list, NULL);
1193         ok(res == S_OK, "NdrDllUnregisterProxy failed %x\n",res);
1194     }
1195 }
1196 
1197 START_TEST( cstub )
1198 {
1199     IPSFactoryBuffer *ppsf;
1200 
1201     OleInitialize(NULL);
1202 
1203     ppsf = test_NdrDllGetClassObject();
1204     test_NdrStubForwardingFunction();
1205     test_CreateProxy(ppsf);
1206     test_CreateStub(ppsf);
1207     test_Connect(ppsf);
1208     test_Disconnect(ppsf);
1209     test_Release(ppsf);
1210     test_delegating_Invoke(ppsf);
1211     test_NdrDllRegisterProxy();
1212 
1213     OleUninitialize();
1214 }
1215