1 /*
2  * Unit test suite for ndr marshalling functions
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 #define _WIN32_WINNT  0x0500
22 #define NTDDI_WIN2K   0x05000000
23 #define NTDDI_VERSION NTDDI_WIN2K /* for some MIDL_STUB_MESSAGE fields */
24 #define COBJMACROS
25 
26 #include <stdarg.h>
27 
28 #include <windef.h>
29 #include <winbase.h>
30 #include <winnt.h>
31 #include <winerror.h>
32 #include <ole2.h>
33 
34 #include "rpc.h"
35 #include "rpcdce.h"
36 #include "rpcproxy.h"
37 #include "midles.h"
38 #include "ndrtypes.h"
39 
40 #include "wine/heap.h"
41 #include "wine/test.h"
42 
43 static int my_alloc_called;
44 static int my_free_called;
45 static void * CALLBACK my_alloc(SIZE_T size)
46 {
47     my_alloc_called++;
48     return NdrOleAllocate(size);
49 }
50 
51 static void CALLBACK my_free(void *ptr)
52 {
53     my_free_called++;
54     NdrOleFree(ptr);
55 }
56 
57 static const MIDL_STUB_DESC Object_StubDesc =
58     {
59     NULL,
60     my_alloc,
61     my_free,
62     { 0 },
63     0,
64     0,
65     0,
66     0,
67     NULL, /* format string, filled in by tests */
68     1, /* -error bounds_check flag */
69     0x20000, /* Ndr library version */
70     0,
71     0x50100a4, /* MIDL Version 5.1.164 */
72     0,
73     NULL,
74     0,  /* notify & notify_flag routine table */
75     1,  /* Flags */
76     0,  /* Reserved3 */
77     0,  /* Reserved4 */
78     0   /* Reserved5 */
79     };
80 
81 static RPC_DISPATCH_FUNCTION IFoo_table[] =
82 {
83     0
84 };
85 
86 static RPC_DISPATCH_TABLE IFoo_v0_0_DispatchTable =
87 {
88     0,
89     IFoo_table
90 };
91 
92 static const RPC_SERVER_INTERFACE IFoo___RpcServerInterface =
93 {
94     sizeof(RPC_SERVER_INTERFACE),
95     {{0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x34}},{0,0}},
96     {{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}},
97     &IFoo_v0_0_DispatchTable,
98     0,
99     0,
100     0,
101     0,
102     0,
103 };
104 
105 static RPC_IF_HANDLE IFoo_v0_0_s_ifspec = (RPC_IF_HANDLE)& IFoo___RpcServerInterface;
106 static BOOL use_pointer_ids = FALSE;
107 
108 static void determine_pointer_marshalling_style(void)
109 {
110     RPC_MESSAGE RpcMessage;
111     MIDL_STUB_MESSAGE StubMsg;
112     MIDL_STUB_DESC StubDesc;
113     char ch = 0xde;
114 
115     static const unsigned char fmtstr_up_char[] =
116     {
117         0x12, 0x8,      /* FC_UP [simple_pointer] */
118         0x2,            /* FC_CHAR */
119         0x5c,           /* FC_PAD */
120     };
121 
122     StubDesc = Object_StubDesc;
123     StubDesc.pFormatTypes = NULL;
124 
125     NdrClientInitializeNew(
126                            &RpcMessage,
127                            &StubMsg,
128                            &StubDesc,
129                            0);
130 
131     StubMsg.BufferLength = 8;
132     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
133     NdrPointerMarshall(&StubMsg, (unsigned char*)&ch, fmtstr_up_char);
134     ok(StubMsg.Buffer == StubMsg.BufferStart + 5, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart);
135 
136     use_pointer_ids = (*(unsigned int *)StubMsg.BufferStart != (UINT_PTR)&ch);
137     trace("Pointer marshalling using %s\n", use_pointer_ids ? "pointer ids" : "pointer value");
138 
139     HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart);
140 }
141 
142 static void test_ndr_simple_type(void)
143 {
144     RPC_MESSAGE RpcMessage;
145     MIDL_STUB_MESSAGE StubMsg;
146     MIDL_STUB_DESC StubDesc;
147     LONG l, l2 = 0;
148 
149     StubDesc = Object_StubDesc;
150     StubDesc.pFormatTypes = NULL;
151 
152     NdrClientInitializeNew(
153                            &RpcMessage,
154                            &StubMsg,
155                            &StubDesc,
156                            0);
157 
158     StubMsg.BufferLength = 16;
159     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
160     l = 0xcafebabe;
161     NdrSimpleTypeMarshall(&StubMsg, (unsigned char*)&l, FC_LONG);
162     ok(StubMsg.Buffer == StubMsg.BufferStart + 4, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart);
163     ok(*(LONG*)StubMsg.BufferStart == l, "%d\n", *(LONG*)StubMsg.BufferStart);
164 
165     StubMsg.Buffer = StubMsg.BufferStart + 1;
166     NdrSimpleTypeMarshall(&StubMsg, (unsigned char*)&l, FC_LONG);
167     ok(StubMsg.Buffer == StubMsg.BufferStart + 8, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart);
168     ok(*(LONG*)(StubMsg.BufferStart + 4) == l, "%d\n", *(LONG*)StubMsg.BufferStart);
169 
170     StubMsg.Buffer = StubMsg.BufferStart + 1;
171     NdrSimpleTypeUnmarshall(&StubMsg, (unsigned char*)&l2, FC_LONG);
172     ok(StubMsg.Buffer == StubMsg.BufferStart + 8, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart);
173     ok(l2 == l, "%d\n", l2);
174 
175     HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart);
176 }
177 
178 static void test_pointer_marshal(const unsigned char *formattypes,
179                                  void *memsrc, DWORD srcsize,
180                                  const void *wiredata,
181                                  ULONG wiredatalen,
182                                  int(*cmp)(const void*,const void*,size_t),
183                                  int num_additional_allocs,
184                                  const char *msgpfx)
185 {
186     RPC_MESSAGE RpcMessage;
187     MIDL_STUB_MESSAGE StubMsg;
188     MIDL_STUB_DESC StubDesc;
189     DWORD size;
190     void *ptr;
191     unsigned char *mem, *mem_orig;
192 
193     if(!cmp)
194         cmp = memcmp;
195 
196     StubDesc = Object_StubDesc;
197     StubDesc.pFormatTypes = formattypes;
198 
199     NdrClientInitializeNew(
200                            &RpcMessage,
201                            &StubMsg,
202                            &StubDesc,
203                            0);
204 
205     StubMsg.BufferLength = 0;
206     NdrPointerBufferSize( &StubMsg,
207                           memsrc,
208                           formattypes );
209     ok(StubMsg.BufferLength >= wiredatalen, "%s: length %d\n", msgpfx, StubMsg.BufferLength);
210 
211     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
212     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
213     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
214 
215     memset(StubMsg.BufferStart, 0x0, StubMsg.BufferLength); /* This is a hack to clear the padding between the ptr and longlong/double */
216 
217     ptr = NdrPointerMarshall( &StubMsg,  memsrc, formattypes );
218     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
219     if (srcsize == 8 && wiredatalen == 16 && StubMsg.Buffer - StubMsg.BufferStart == 12)
220     {
221         /* win9x doesn't align 8-byte types properly */
222         wiredatalen = 12;
223     }
224     else
225     {
226         ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
227         ok(!memcmp(StubMsg.BufferStart, wiredata, wiredatalen), "%s: incorrectly marshaled\n", msgpfx);
228     }
229 
230     StubMsg.Buffer = StubMsg.BufferStart;
231     StubMsg.MemorySize = 0;
232 
233     size = NdrPointerMemorySize( &StubMsg, formattypes );
234     ok(size == StubMsg.MemorySize, "%s: mem size %u size %u\n", msgpfx, StubMsg.MemorySize, size);
235     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
236     if (formattypes[1] & FC_POINTER_DEREF)
237         ok(size == srcsize + sizeof(void *), "%s: mem size %u\n", msgpfx, size);
238     else
239         ok(size == srcsize, "%s: mem size %u\n", msgpfx, size);
240 
241     StubMsg.Buffer = StubMsg.BufferStart;
242     StubMsg.MemorySize = 16;
243     size = NdrPointerMemorySize( &StubMsg, formattypes );
244     ok(size == StubMsg.MemorySize, "%s: mem size %u size %u\n", msgpfx, StubMsg.MemorySize, size);
245     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
246     if (formattypes[1] & FC_POINTER_DEREF)
247         ok(size == srcsize + sizeof(void *) + 16, "%s: mem size %u\n", msgpfx, size);
248     else
249         ok(size == srcsize + 16, "%s: mem size %u\n", msgpfx, size);
250 
251     StubMsg.Buffer = StubMsg.BufferStart;
252     StubMsg.MemorySize = 1;
253     size = NdrPointerMemorySize( &StubMsg, formattypes );
254     ok(size == StubMsg.MemorySize, "%s: mem size %u size %u\n", msgpfx, StubMsg.MemorySize, size);
255     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
256     if (formattypes[1] & FC_POINTER_DEREF)
257         ok(size == srcsize + sizeof(void *) + (srcsize == 8 ? 8 : sizeof(void *)), "%s: mem size %u\n", msgpfx, size);
258     else
259         ok(size == srcsize + (srcsize == 8 ? 8 : sizeof(void *)), "%s: mem size %u\n", msgpfx, size);
260 
261     size = srcsize;
262     if (formattypes[1] & FC_POINTER_DEREF) size += 4;
263 
264     StubMsg.Buffer = StubMsg.BufferStart;
265     StubMsg.MemorySize = 0;
266     /* Using my_alloc() here is necessary to prevent a crash in Windows 7+. */
267     mem_orig = mem = my_alloc(size);
268     memset(mem, 0, size);
269     my_alloc_called = my_free_called = 0;
270     if (formattypes[1] & FC_POINTER_DEREF)
271         *(void**)mem = NULL;
272     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
273     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
274     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
275     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
276     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
277     ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
278     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
279     /* On Windows 7+ unmarshalling may involve calls to NdrFree, for unclear reasons. */
280     my_free_called = 0;
281 
282     NdrPointerFree(&StubMsg, mem, formattypes);
283     if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
284     {
285         /* In this case the top-level pointer is not freed. */
286         ok(my_free_called == num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
287         HeapFree(GetProcessHeap(), 0, mem);
288     }
289     else
290         ok(my_free_called == 1 + num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
291 
292     /* reset the buffer and call with must alloc */
293     my_alloc_called = my_free_called = 0;
294     StubMsg.Buffer = StubMsg.BufferStart;
295     mem_orig = mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
296     if (formattypes[1] & FC_POINTER_DEREF)
297         *(void**)mem = NULL;
298     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 1 );
299     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
300     /* doesn't allocate mem in this case */
301     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
302     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
303     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
304     ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
305     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
306     ok(!my_free_called, "%s: my_free got called %d times\n", msgpfx, my_free_called);
307 
308     NdrPointerFree(&StubMsg, mem, formattypes);
309     if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
310     {
311         /* In this case the top-level pointer is not freed. */
312         ok(my_free_called == num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
313         HeapFree(GetProcessHeap(), 0, mem);
314     }
315     else
316         ok(my_free_called == 1 + num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
317 
318     if (formattypes[0] != FC_RP)
319     {
320         /* now pass the address of a NULL ptr */
321         mem = NULL;
322         my_alloc_called = my_free_called = 0;
323         StubMsg.Buffer = StubMsg.BufferStart;
324         ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
325         ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
326         ok(mem != StubMsg.BufferStart + wiredatalen - srcsize, "%s: mem points to buffer %p %p\n", msgpfx, mem, StubMsg.BufferStart);
327         ok(!cmp(mem, memsrc, size), "%s: incorrectly unmarshaled\n", msgpfx);
328         ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
329         ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
330         ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
331         my_alloc_called = 0;
332         NdrPointerFree(&StubMsg, mem, formattypes);
333 
334         /* again pass address of NULL ptr, but pretend we're a server */
335         if (0)  /* crashes on Win9x and NT4 */
336         {
337             mem = NULL;
338             StubMsg.Buffer = StubMsg.BufferStart;
339             StubMsg.IsClient = 0;
340             ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
341             ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
342             if (formattypes[2] == FC_ENUM16)
343                 ok(mem != StubMsg.BufferStart + wiredatalen - srcsize, "%s: mem points to buffer %p %p\n", msgpfx, mem, StubMsg.BufferStart);
344             else
345                 ok(mem == StubMsg.BufferStart + wiredatalen - srcsize, "%s: mem doesn't point to buffer %p %p\n", msgpfx, mem, StubMsg.BufferStart);
346             ok(!cmp(mem, memsrc, size), "%s: incorrectly unmarshaled\n", msgpfx);
347             ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
348             ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
349             if (formattypes[2] != FC_ENUM16)
350             {
351                 ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
352                 my_alloc_called = 0;
353             }
354         }
355     }
356 
357     /* Server */
358     StubMsg.IsClient = 0;
359 
360     /* For most basetypes (but not enum16), memory will not be allocated but
361      * instead point directly to the buffer. */
362     my_alloc_called = my_free_called = 0;
363     StubMsg.Buffer = StubMsg.BufferStart;
364     mem = NULL;
365     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
366     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
367     ok(!!mem, "%s: mem was not allocated\n", msgpfx);
368     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
369     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
370     ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
371     if (formattypes[2] == FC_ENUM16)
372         ok(my_alloc_called == 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
373     else
374         ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
375     ok(!my_free_called, "%s: my_free got called %d times\n", msgpfx, my_free_called);
376 
377     NdrPointerFree(&StubMsg, mem, formattypes);
378     if (formattypes[2] == FC_ENUM16)
379         ok(my_free_called == 1, "%s: my_free got called %d times\n", msgpfx, my_free_called);
380     else if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
381     {
382         /* In theory this should be freed to correspond with the allocation, but
383          * FC_ALLOCED_ON_STACK is set, and NdrPointerFree() has no way of
384          * knowing that the memory allocated by NdrPointerUnmarshall() isn't
385          * stack memory. In practice it always *is* stack memory if ON_STACK is
386          * set, so this leak isn't a concern. */
387         ok(my_free_called == 0, "%s: my_free got called %d times\n", msgpfx, my_free_called);
388         HeapFree(GetProcessHeap(), 0, mem);
389     }
390     else
391         ok(my_free_called == num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
392 
393     /* reset the buffer and call with must alloc */
394     my_alloc_called = my_free_called = 0;
395     StubMsg.Buffer = StubMsg.BufferStart;
396     mem = NULL;
397     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 1 );
398     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
399     ok(!!mem, "%s: mem was not allocated\n", msgpfx);
400     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
401     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
402     ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
403     if (formattypes[2] == FC_ENUM16)
404         ok(my_alloc_called == 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
405     else
406         ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
407     ok(!my_free_called, "%s: my_free got called %d times\n", msgpfx, my_free_called);
408 
409     NdrPointerFree(&StubMsg, mem, formattypes);
410     if (formattypes[2] == FC_ENUM16)
411         ok(my_free_called == 1, "%s: my_free got called %d times\n", msgpfx, my_free_called);
412     else if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
413     {
414         ok(my_free_called == 0, "%s: my_free got called %d times\n", msgpfx, my_free_called);
415         HeapFree(GetProcessHeap(), 0, mem);
416     }
417     else
418         ok(my_free_called == num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
419 
420     /* Τest with an existing pointer. Unless it's a stack pointer (and deref'd)
421      * a new pointer will be allocated anyway (in fact, an invalid pointer works
422      * in every such case). */
423 
424     my_alloc_called = my_free_called = 0;
425     StubMsg.Buffer = StubMsg.BufferStart;
426     mem_orig = mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
427     if (formattypes[1] & FC_POINTER_DEREF)
428         *(void**)mem = NULL;
429     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
430     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
431     if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
432         ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
433     else
434     {
435         ok(mem != mem_orig, "%s: mem has not changed\n", msgpfx);
436         HeapFree(GetProcessHeap(), 0, mem_orig);
437     }
438     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
439     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
440     ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
441     if (formattypes[2] == FC_ENUM16)
442         ok(my_alloc_called == 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
443     else if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
444         ok(my_alloc_called == 0, "%s: my_alloc got called %d times\n", msgpfx, my_free_called);
445     else
446         ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
447     ok(!my_free_called, "%s: my_free got called %d times\n", msgpfx, my_free_called);
448 
449     NdrPointerFree(&StubMsg, mem, formattypes);
450     if (formattypes[2] == FC_ENUM16)
451         ok(my_free_called == 1, "%s: my_free got called %d times\n", msgpfx, my_free_called);
452     else if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
453     {
454         ok(my_free_called == 0, "%s: my_free got called %d times\n", msgpfx, my_free_called);
455         HeapFree(GetProcessHeap(), 0, mem);
456     }
457     else
458         ok(my_free_called == num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
459 
460     /* reset the buffer and call with must alloc */
461     my_alloc_called = my_free_called = 0;
462     StubMsg.Buffer = StubMsg.BufferStart;
463     mem_orig = mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
464     if (formattypes[1] & FC_POINTER_DEREF)
465         *(void**)mem = NULL;
466     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 1 );
467     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
468     if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
469         ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
470     else
471     {
472         ok(mem != mem_orig, "%s: mem has not changed\n", msgpfx);
473         HeapFree(GetProcessHeap(), 0, mem_orig);
474     }
475     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
476     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
477     ok(StubMsg.MemorySize == 0, "%s: memorysize %d\n", msgpfx, StubMsg.MemorySize);
478     if (formattypes[2] == FC_ENUM16)
479         ok(my_alloc_called == 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
480     else if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
481         ok(my_alloc_called == 0, "%s: my_alloc got called %d times\n", msgpfx, my_free_called);
482     else
483         ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
484     ok(!my_free_called, "%s: my_free got called %d times\n", msgpfx, my_free_called);
485 
486     NdrPointerFree(&StubMsg, mem, formattypes);
487     if (formattypes[2] == FC_ENUM16)
488         ok(my_free_called == 1, "%s: my_free got called %d times\n", msgpfx, my_free_called);
489     else if ((formattypes[1] & FC_ALLOCED_ON_STACK) && (formattypes[1] & FC_POINTER_DEREF))
490     {
491         ok(my_free_called == 0, "%s: my_free got called %d times\n", msgpfx, my_free_called);
492         HeapFree(GetProcessHeap(), 0, mem);
493     }
494     else
495         ok(my_free_called == num_additional_allocs, "%s: my_free got called %d times\n", msgpfx, my_free_called);
496 
497     HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart);
498 }
499 
500 static int deref_cmp(const void *s1, const void *s2, size_t num)
501 {
502     return memcmp(*(const void *const *)s1, *(const void *const *)s2, num);
503 }
504 
505 
506 static void test_simple_types(void)
507 {
508     unsigned char wiredata[16];
509     unsigned char ch;
510     unsigned char *ch_ptr;
511     unsigned short s;
512     unsigned int i;
513     ULONG l;
514     ULONGLONG ll;
515     float f;
516     double d;
517 
518     static const unsigned char fmtstr_up_char[] =
519     {
520         0x12, 0x8,      /* FC_UP [simple_pointer] */
521         0x2,            /* FC_CHAR */
522         0x5c,           /* FC_PAD */
523     };
524     static const unsigned char fmtstr_up_byte[] =
525     {
526         0x12, 0x8,      /* FC_UP [simple_pointer] */
527         0x1,            /* FC_BYTE */
528         0x5c,           /* FC_PAD */
529     };
530     static const unsigned char fmtstr_up_small[] =
531     {
532         0x12, 0x8,      /* FC_UP [simple_pointer] */
533         0x3,            /* FC_SMALL */
534         0x5c,           /* FC_PAD */
535     };
536     static const unsigned char fmtstr_up_usmall[] =
537     {
538         0x12, 0x8,      /* FC_UP [simple_pointer] */
539         0x4,            /* FC_USMALL */
540         0x5c,           /* FC_PAD */
541     };
542     static const unsigned char fmtstr_rp_char[] =
543     {
544         0x11, 0x8,      /* FC_RP [simple_pointer] */
545         0x2,            /* FC_CHAR */
546         0x5c,           /* FC_PAD */
547     };
548     static const unsigned char fmtstr_rpup_char_onstack_deref[] =
549     {
550         0x11, 0x14,     /* FC_RP [alloced_on_stack] [pointer_deref] */
551         NdrFcShort( 0x2 ),      /* Offset= 2 (4) */
552         0x12, 0x8,      /* FC_UP [simple_pointer] */
553         0x2,            /* FC_CHAR */
554         0x5c,           /* FC_PAD */
555     };
556     static const unsigned char fmtstr_rpup_char_onstack[] =
557     {
558         0x11, 0x04,     /* FC_RP [alloced_on_stack] */
559         NdrFcShort( 0x2 ),      /* Offset= 2 (4) */
560         0x12, 0x8,      /* FC_UP [simple_pointer] */
561         0x2,            /* FC_CHAR */
562         0x5c,           /* FC_PAD */
563     };
564     static const unsigned char fmtstr_rpup_char_deref[] =
565     {
566         0x11, 0x10,     /* FC_RP [pointer_deref] */
567         NdrFcShort( 0x2 ),      /* Offset= 2 (4) */
568         0x12, 0x8,      /* FC_UP [simple_pointer] */
569         0x2,            /* FC_CHAR */
570         0x5c,           /* FC_PAD */
571     };
572 
573     static const unsigned char fmtstr_up_wchar[] =
574     {
575         0x12, 0x8,      /* FC_UP [simple_pointer] */
576         0x5,            /* FC_WCHAR */
577         0x5c,           /* FC_PAD */
578     };
579     static const unsigned char fmtstr_up_short[] =
580     {
581         0x12, 0x8,      /* FC_UP [simple_pointer] */
582         0x6,            /* FC_SHORT */
583         0x5c,           /* FC_PAD */
584     };
585     static const unsigned char fmtstr_up_ushort[] =
586     {
587         0x12, 0x8,      /* FC_UP [simple_pointer] */
588         0x7,            /* FC_USHORT */
589         0x5c,           /* FC_PAD */
590     };
591     static const unsigned char fmtstr_up_enum16[] =
592     {
593         0x12, 0x8,      /* FC_UP [simple_pointer] */
594         0xd,            /* FC_ENUM16 */
595         0x5c,           /* FC_PAD */
596     };
597     static const unsigned char fmtstr_up_long[] =
598     {
599         0x12, 0x8,      /* FC_UP [simple_pointer] */
600         0x8,            /* FC_LONG */
601         0x5c,           /* FC_PAD */
602     };
603     static const unsigned char fmtstr_up_ulong[] =
604     {
605         0x12, 0x8,      /* FC_UP [simple_pointer] */
606         0x9,            /* FC_ULONG */
607         0x5c,           /* FC_PAD */
608     };
609     static const unsigned char fmtstr_up_enum32[] =
610     {
611         0x12, 0x8,      /* FC_UP [simple_pointer] */
612         0xe,            /* FC_ENUM32 */
613         0x5c,           /* FC_PAD */
614     };
615     static const unsigned char fmtstr_up_errorstatus[] =
616     {
617         0x12, 0x8,      /* FC_UP [simple_pointer] */
618         0x10,           /* FC_ERROR_STATUS_T */
619         0x5c,           /* FC_PAD */
620     };
621 
622     static const unsigned char fmtstr_up_longlong[] =
623     {
624         0x12, 0x8,      /* FC_UP [simple_pointer] */
625         0xb,            /* FC_HYPER */
626         0x5c,           /* FC_PAD */
627     };
628     static const unsigned char fmtstr_up_float[] =
629     {
630         0x12, 0x8,      /* FC_UP [simple_pointer] */
631         0xa,            /* FC_FLOAT */
632         0x5c,           /* FC_PAD */
633     };
634     static const unsigned char fmtstr_up_double[] =
635     {
636         0x12, 0x8,      /* FC_UP [simple_pointer] */
637         0xc,            /* FC_DOUBLE */
638         0x5c,           /* FC_PAD */
639     };
640 
641     ch = 0xa5;
642     ch_ptr = &ch;
643     if (use_pointer_ids)
644         *(unsigned int *)wiredata = 0x20000;
645     else
646         *(unsigned int *)wiredata = (UINT_PTR)ch_ptr;
647     wiredata[4] = ch;
648 
649     test_pointer_marshal(fmtstr_up_char, ch_ptr, 1, wiredata, 5, NULL, 0, "up_char");
650     test_pointer_marshal(fmtstr_up_byte, ch_ptr, 1, wiredata, 5, NULL, 0, "up_byte");
651     test_pointer_marshal(fmtstr_up_small, ch_ptr, 1, wiredata, 5, NULL, 0,  "up_small");
652     test_pointer_marshal(fmtstr_up_usmall, ch_ptr, 1, wiredata, 5, NULL, 0, "up_usmall");
653 
654     test_pointer_marshal(fmtstr_rp_char, ch_ptr, 1, &ch, 1, NULL, 0, "rp_char");
655 
656     test_pointer_marshal(fmtstr_rpup_char_onstack_deref, &ch_ptr, 1, wiredata, 5, deref_cmp, 1, "rpup_char_onstack_deref");
657     test_pointer_marshal(fmtstr_rpup_char_onstack, ch_ptr, 1, wiredata, 5, NULL, 0, "rpup_char_onstack");
658     test_pointer_marshal(fmtstr_rpup_char_deref, &ch_ptr, 1, wiredata, 5, deref_cmp, 1, "rpup_char_deref");
659 
660     s = 0xa597;
661     if (use_pointer_ids)
662         *(unsigned int *)wiredata = 0x20000;
663     else
664         *(unsigned int *)wiredata = (UINT_PTR)&s;
665     *(unsigned short*)(wiredata + 4) = s;
666 
667     test_pointer_marshal(fmtstr_up_wchar, &s, 2, wiredata, 6, NULL, 0, "up_wchar");
668     test_pointer_marshal(fmtstr_up_short, &s, 2, wiredata, 6, NULL, 0, "up_short");
669     test_pointer_marshal(fmtstr_up_ushort, &s, 2, wiredata, 6, NULL, 0, "up_ushort");
670 
671     i = 0x7fff;
672     if (use_pointer_ids)
673         *(unsigned int *)wiredata = 0x20000;
674     else
675         *(unsigned int *)wiredata = (UINT_PTR)&i;
676     *(unsigned short*)(wiredata + 4) = i;
677     test_pointer_marshal(fmtstr_up_enum16, &i, 4, wiredata, 6, NULL, 0, "up_enum16");
678 
679     l = 0xcafebabe;
680     if (use_pointer_ids)
681         *(unsigned int *)wiredata = 0x20000;
682     else
683         *(unsigned int *)wiredata = (UINT_PTR)&l;
684     *(ULONG*)(wiredata + 4) = l;
685 
686     test_pointer_marshal(fmtstr_up_long, &l, 4, wiredata, 8, NULL, 0, "up_long");
687     test_pointer_marshal(fmtstr_up_ulong, &l, 4, wiredata, 8, NULL, 0,  "up_ulong");
688     test_pointer_marshal(fmtstr_up_enum32, &l, 4, wiredata, 8, NULL, 0,  "up_emun32");
689     test_pointer_marshal(fmtstr_up_errorstatus, &l, 4, wiredata, 8, NULL, 0,  "up_errorstatus");
690 
691     ll = ((ULONGLONG)0xcafebabe) << 32 | 0xdeadbeef;
692     if (use_pointer_ids)
693         *(unsigned int *)wiredata = 0x20000;
694     else
695         *(unsigned int *)wiredata = (UINT_PTR)&ll;
696     *(unsigned int *)(wiredata + 4) = 0;
697     *(ULONGLONG*)(wiredata + 8) = ll;
698     test_pointer_marshal(fmtstr_up_longlong, &ll, 8, wiredata, 16, NULL, 0, "up_longlong");
699 
700     f = 3.1415f;
701     if (use_pointer_ids)
702         *(unsigned int *)wiredata = 0x20000;
703     else
704         *(unsigned int *)wiredata = (UINT_PTR)&f;
705     *(float*)(wiredata + 4) = f;
706     test_pointer_marshal(fmtstr_up_float, &f, 4, wiredata, 8, NULL, 0, "up_float");
707 
708     d = 3.1415;
709     if (use_pointer_ids)
710         *(unsigned int *)wiredata = 0x20000;
711     else
712         *(unsigned int *)wiredata = (UINT_PTR)&d;
713     *(unsigned int *)(wiredata + 4) = 0;
714     *(double*)(wiredata + 8) = d;
715     test_pointer_marshal(fmtstr_up_double, &d, 8, wiredata, 16, NULL, 0,  "up_double");
716 
717 }
718 
719 static void test_nontrivial_pointer_types(void)
720 {
721     RPC_MESSAGE RpcMessage;
722     MIDL_STUB_MESSAGE StubMsg;
723     MIDL_STUB_DESC StubDesc;
724     DWORD size;
725     void *ptr;
726     char **p1;
727     char *p2;
728     char ch;
729     unsigned char *mem, *mem_orig;
730 
731     static const unsigned char fmtstr_ref_unique_out[] =
732     {
733         0x12, 0x8,	/* FC_UP [simple_pointer] */
734         0x2,		/* FC_CHAR */
735         0x5c,		/* FC_PAD */
736         0x11, 0x14,	/* FC_RP [alloced_on_stack] [pointer_deref] */
737         NdrFcShort( 0xfffffffa ),	/* Offset= -6 (0) */
738     };
739 
740     p1 = &p2;
741     p2 = &ch;
742     ch = 0x22;
743 
744     StubDesc = Object_StubDesc;
745     StubDesc.pFormatTypes = fmtstr_ref_unique_out;
746 
747     NdrClientInitializeNew(
748                            &RpcMessage,
749                            &StubMsg,
750                            &StubDesc,
751                            0);
752 
753     StubMsg.BufferLength = 0;
754     NdrPointerBufferSize( &StubMsg,
755                           (unsigned char *)p1,
756                           &fmtstr_ref_unique_out[4] );
757 
758     /* Windows overestimates the buffer size */
759     ok(StubMsg.BufferLength >= 5, "length %d\n", StubMsg.BufferLength);
760 
761     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
762     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
763     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
764 
765     ptr = NdrPointerMarshall( &StubMsg, (unsigned char *)p1, &fmtstr_ref_unique_out[4] );
766     ok(ptr == NULL, "ret %p\n", ptr);
767     size = StubMsg.Buffer - StubMsg.BufferStart;
768     ok(size == 5, "Buffer %p Start %p len %d\n", StubMsg.Buffer, StubMsg.BufferStart, size);
769     ok(*(unsigned int *)StubMsg.BufferStart != 0, "pointer ID marshalled incorrectly\n");
770     ok(*(unsigned char *)(StubMsg.BufferStart + 4) == 0x22, "char data marshalled incorrectly: 0x%x\n",
771        *(unsigned char *)(StubMsg.BufferStart + 4));
772 
773     StubMsg.Buffer = StubMsg.BufferStart;
774     StubMsg.MemorySize = 0;
775     mem = NULL;
776 
777     /* Client */
778     my_alloc_called = 0;
779     StubMsg.Buffer = StubMsg.BufferStart;
780     mem = mem_orig = HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
781     *(void **)mem = NULL;
782     NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 0);
783     ok(mem == mem_orig, "mem alloced\n");
784     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
785 
786     my_alloc_called = 0;
787     StubMsg.Buffer = StubMsg.BufferStart;
788     NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 1);
789     ok(mem == mem_orig, "mem alloced\n");
790     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
791 
792     my_free_called = 0;
793     StubMsg.Buffer = StubMsg.BufferStart;
794     NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] );
795     ok(my_free_called == 1, "free called %d\n", my_free_called);
796 
797     mem = my_alloc(sizeof(void *));
798     *(void **)mem = NULL;
799     my_free_called = 0;
800     StubMsg.Buffer = StubMsg.BufferStart;
801     NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] );
802     ok(my_free_called == 0, "free called %d\n", my_free_called);
803     my_free(mem);
804 
805     mem = my_alloc(sizeof(void *));
806     *(void **)mem = my_alloc(sizeof(char));
807     my_free_called = 0;
808     StubMsg.Buffer = StubMsg.BufferStart;
809     NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] );
810     ok(my_free_called == 1, "free called %d\n", my_free_called);
811     my_free(mem);
812 
813     /* Server */
814     my_alloc_called = 0;
815     my_free_called = 0;
816     StubMsg.IsClient = 0;
817     mem = NULL;
818     StubMsg.Buffer = StubMsg.BufferStart;
819     NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 0);
820     ok(mem != StubMsg.BufferStart, "mem pointing at buffer\n");
821     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
822     NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] );
823     ok(my_free_called == 0, "free called %d\n", my_free_called);
824     my_free(mem);
825 
826     my_alloc_called = 0;
827     my_free_called = 0;
828     mem = NULL;
829     StubMsg.Buffer = StubMsg.BufferStart;
830     NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 1);
831     ok(mem != StubMsg.BufferStart, "mem pointing at buffer\n");
832     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
833     NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] );
834     ok(my_free_called == 0, "free called %d\n", my_free_called);
835     my_free(mem);
836 
837     my_alloc_called = 0;
838     mem = mem_orig;
839     *(void **)mem = NULL;
840     StubMsg.Buffer = StubMsg.BufferStart;
841     NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 0);
842     ok(mem == mem_orig, "mem alloced\n");
843     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
844 
845     my_alloc_called = 0;
846     mem = mem_orig;
847     *(void **)mem = NULL;
848     StubMsg.Buffer = StubMsg.BufferStart;
849     NdrPointerUnmarshall( &StubMsg, &mem, &fmtstr_ref_unique_out[4], 1);
850     ok(mem == mem_orig, "mem alloced\n");
851     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
852 
853     mem = my_alloc(sizeof(void *));
854     *(void **)mem = NULL;
855     my_free_called = 0;
856     StubMsg.Buffer = StubMsg.BufferStart;
857     NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] );
858     ok(my_free_called == 0, "free called %d\n", my_free_called);
859     my_free(mem);
860 
861     mem = my_alloc(sizeof(void *));
862     *(void **)mem = my_alloc(sizeof(char));
863     my_free_called = 0;
864     StubMsg.Buffer = StubMsg.BufferStart;
865     NdrPointerFree( &StubMsg, mem, &fmtstr_ref_unique_out[4] );
866     ok(my_free_called == 1, "free called %d\n", my_free_called);
867     my_free(mem);
868 
869     HeapFree(GetProcessHeap(), 0, mem_orig);
870     HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer);
871 }
872 
873 static void test_simple_struct_marshal(const unsigned char *formattypes,
874                                        void *memsrc, DWORD srcsize,
875                                        const void *wiredata,
876                                        ULONG wiredatalen,
877                                        int(*cmp)(const void*,const void*,size_t),
878                                        int num_additional_allocs,
879                                        const char *msgpfx)
880 {
881     RPC_MESSAGE RpcMessage;
882     MIDL_STUB_MESSAGE StubMsg;
883     MIDL_STUB_DESC StubDesc;
884     DWORD size;
885     void *ptr;
886     unsigned char *mem, *mem_orig;
887 
888     my_alloc_called = my_free_called = 0;
889     if(!cmp)
890         cmp = memcmp;
891 
892     StubDesc = Object_StubDesc;
893     StubDesc.pFormatTypes = formattypes;
894 
895     NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0);
896 
897     StubMsg.BufferLength = 0;
898     NdrSimpleStructBufferSize( &StubMsg, memsrc, formattypes );
899     ok(StubMsg.BufferLength >= wiredatalen, "%s: length %d\n", msgpfx, StubMsg.BufferLength);
900     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
901     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
902     ptr = NdrSimpleStructMarshall( &StubMsg,  memsrc, formattypes );
903     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
904     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
905     ok(!memcmp(StubMsg.BufferStart, wiredata, wiredatalen), "%s: incorrectly marshaled %08x %08x %08x\n", msgpfx, *(DWORD*)StubMsg.BufferStart,*((DWORD*)StubMsg.BufferStart+1),*((DWORD*)StubMsg.BufferStart+2));
906 
907     StubMsg.Buffer = StubMsg.BufferStart;
908     StubMsg.MemorySize = 0;
909     size = NdrSimpleStructMemorySize( &StubMsg, formattypes );
910     ok(size == StubMsg.MemorySize, "%s: size != MemorySize\n", msgpfx);
911     ok(size == srcsize, "%s: mem size %u\n", msgpfx, size);
912     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
913 
914     StubMsg.Buffer = StubMsg.BufferStart;
915     size = NdrSimpleStructMemorySize( &StubMsg, formattypes );
916     ok(size == StubMsg.MemorySize, "%s: size != MemorySize\n", msgpfx);
917     ok(StubMsg.MemorySize == ((srcsize + 3) & ~3) + srcsize, "%s: mem size %u\n", msgpfx, size);
918     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
919     size = srcsize;
920     /*** Unmarshalling first with must_alloc false ***/
921 
922     StubMsg.Buffer = StubMsg.BufferStart;
923     StubMsg.MemorySize = 0;
924     mem_orig = mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, srcsize);
925     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 0 );
926     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
927     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
928     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
929     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
930     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
931     my_alloc_called = 0;
932     my_free_called = 0;
933     ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx);
934     NdrSimpleStructFree(&StubMsg, mem, formattypes );
935     ok(my_free_called == num_additional_allocs, "free called %d\n", my_free_called);
936 
937     /* If we're a server we still use the supplied memory */
938     StubMsg.Buffer = StubMsg.BufferStart;
939     StubMsg.IsClient = 0;
940     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 0 );
941     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
942     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
943     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
944     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
945     my_alloc_called = 0;
946     my_free_called = 0;
947     ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx);
948     NdrSimpleStructFree(&StubMsg, mem, formattypes );
949     ok(my_free_called == num_additional_allocs, "free called %d\n", my_free_called);
950 
951     /* ...unless we pass a NULL ptr, then the buffer is used.
952        Passing a NULL ptr while we're a client && !must_alloc
953        crashes on Windows, so we won't do that. */
954 
955     if (0)  /* crashes on Win9x and NT4 */
956     {
957         mem = NULL;
958         StubMsg.IsClient = 0;
959         StubMsg.Buffer = StubMsg.BufferStart;
960         ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, FALSE );
961         ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
962         ok(mem == StubMsg.BufferStart, "%s: mem not equal buffer\n", msgpfx);
963         ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
964         ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
965         my_alloc_called = 0;
966         ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx);
967         NdrSimpleStructFree(&StubMsg, mem, formattypes );
968         ok(my_free_called == num_additional_allocs, "free called %d\n", my_free_called);
969     }
970 
971     /*** now must_alloc is true ***/
972 
973     /* with must_alloc set we always allocate new memory whether or not we're
974        a server and also when passing NULL */
975     mem = mem_orig;
976     StubMsg.IsClient = 1;
977     StubMsg.Buffer = StubMsg.BufferStart;
978     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
979     ok(ptr == NULL, "ret %p\n", ptr);
980     ok(mem != mem_orig, "mem not changed %p %p\n", mem, mem_orig);
981     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n");
982     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
983     my_alloc_called = 0;
984     my_free_called = 0;
985     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
986     NdrSimpleStructFree(&StubMsg, mem, formattypes );
987     ok(my_free_called == num_additional_allocs, "free called %d\n", my_free_called);
988     my_free(mem);
989 
990     mem = NULL;
991     StubMsg.Buffer = StubMsg.BufferStart;
992     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
993     ok(ptr == NULL, "ret %p\n", ptr);
994     ok(mem != mem_orig, "mem not changed %p %p\n", mem, mem_orig);
995     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n");
996     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
997     my_alloc_called = 0;
998     my_free_called = 0;
999     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
1000     NdrSimpleStructFree(&StubMsg, mem, formattypes );
1001     ok(my_free_called == num_additional_allocs, "free called %d\n", my_free_called);
1002     my_free(mem);
1003 
1004     mem = mem_orig;
1005     StubMsg.Buffer = StubMsg.BufferStart;
1006     StubMsg.IsClient = 0;
1007     StubMsg.ReuseBuffer = 1;
1008     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
1009     ok(ptr == NULL, "ret %p\n", ptr);
1010     ok(mem != mem_orig, "mem not changed %p %p\n", mem, mem_orig);
1011     ok(mem != StubMsg.BufferStart, "mem is buffer mem\n");
1012     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n");
1013     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
1014     my_alloc_called = 0;
1015     my_free_called = 0;
1016     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
1017     NdrSimpleStructFree(&StubMsg, mem, formattypes );
1018     ok(my_free_called == num_additional_allocs, "free called %d\n", my_free_called);
1019     my_free(mem);
1020 
1021     mem = NULL;
1022     StubMsg.Buffer = StubMsg.BufferStart;
1023     StubMsg.IsClient = 0;
1024     StubMsg.ReuseBuffer = 1;
1025     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
1026     ok(ptr == NULL, "ret %p\n", ptr);
1027     ok(mem != StubMsg.BufferStart, "mem is buffer mem\n");
1028     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n");
1029     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
1030     my_alloc_called = 0;
1031     my_free_called = 0;
1032     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
1033     NdrSimpleStructFree(&StubMsg, mem, formattypes );
1034     ok(my_free_called == num_additional_allocs, "free called %d\n", my_free_called);
1035     my_free(mem);
1036 
1037     HeapFree(GetProcessHeap(), 0, mem_orig);
1038     HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart);
1039 }
1040 
1041 typedef struct
1042 {
1043     LONG l1;
1044     LONG *pl1;
1045     char *pc1;
1046 } ps1_t;
1047 
1048 static int ps1_cmp(const void *s1, const void *s2, size_t num)
1049 {
1050     const ps1_t *p1, *p2;
1051 
1052     p1 = s1;
1053     p2 = s2;
1054 
1055     if(p1->l1 != p2->l1)
1056         return 1;
1057 
1058     if(p1->pl1 && p2->pl1)
1059     {
1060         if(*p1->pl1 != *p2->pl1)
1061             return 1;
1062     }
1063     else if(p1->pl1 || p2->pl1)
1064         return 1;
1065 
1066     if(p1->pc1 && p2->pc1)
1067     {
1068         if(*p1->pc1 != *p2->pc1)
1069             return 1;
1070     }
1071     else if(p1->pc1 || p2->pc1)
1072         return 1;
1073 
1074     return 0;
1075 }
1076 
1077 static void test_simple_struct(void)
1078 {
1079     unsigned char wiredata[28];
1080     ULONG wiredatalen;
1081     LONG l;
1082     char c;
1083     ps1_t ps1;
1084 
1085     static const unsigned char fmtstr_simple_struct[] =
1086     {
1087         0x12, 0x0,      /* FC_UP */
1088         NdrFcShort( 0x2 ), /* Offset=2 */
1089         0x15, 0x3,      /* FC_STRUCT [align 4] */
1090         NdrFcShort( 0x18 ),      /* [size 24] */
1091         0x6,            /* FC_SHORT */
1092         0x2,            /* FC_CHAR */
1093         0x38,		/* FC_ALIGNM4 */
1094 	0x8,		/* FC_LONG */
1095 	0x8,		/* FC_LONG */
1096         0x39,		/* FC_ALIGNM8 */
1097         0xb,		/* FC_HYPER */
1098         0x5b,		/* FC_END */
1099     };
1100     struct {
1101         short s;
1102         char c;
1103         LONG l1, l2;
1104         LONGLONG ll;
1105     } s1;
1106 
1107     static const unsigned char fmtstr_pointer_struct[] =
1108     {
1109         0x12, 0x0,      /* FC_UP */
1110         NdrFcShort( 0x2 ), /* Offset=2 */
1111 #ifdef _WIN64
1112         0x1a,	/* FC_BOGUS_STRUCT */
1113         0x3,	/* 3 */
1114         NdrFcShort(0x18),	/* [size 24] */
1115         NdrFcShort(0x0),
1116         NdrFcShort(0x8),	/* Offset= 8 (266) */
1117         0x08,	/* FC_LONG */
1118         0x39,	/* FC_ALIGNM8 */
1119         0x36,	/* FC_POINTER */
1120         0x36,	/* FC_POINTER */
1121         0x5c,		/* FC_PAD */
1122         0x5b,		/* FC_END */
1123         0x12, 0x8,	/* FC_UP [simple_pointer] */
1124         0x08,	/* FC_LONG */
1125         0x5c,	/* FC_PAD */
1126         0x12, 0x8,	/* FC_UP [simple_pointer] */
1127         0x02,	/* FC_CHAR */
1128         0x5c,	/* FC_PAD */
1129 #else
1130         0x16, 0x3,      /* FC_PSTRUCT [align 4] */
1131         NdrFcShort( 0xc ),      /* [size 12] */
1132         0x4b,		/* FC_PP */
1133         0x5c,		/* FC_PAD */
1134         0x46,		/* FC_NO_REPEAT */
1135         0x5c,		/* FC_PAD */
1136         NdrFcShort( 0x4 ),	/* 4 */
1137 	NdrFcShort( 0x4 ),	/* 4 */
1138         0x13, 0x8,	/* FC_OP [simple_pointer] */
1139         0x8,		/* FC_LONG */
1140         0x5c,		/* FC_PAD */
1141         0x46,		/* FC_NO_REPEAT */
1142         0x5c,		/* FC_PAD */
1143 	NdrFcShort( 0x8 ),	/* 8 */
1144 	NdrFcShort( 0x8 ),	/* 8 */
1145 	0x13, 0x8,	/* FC_OP [simple_pointer] */
1146         0x2,		/* FC_CHAR */
1147         0x5c,		/* FC_PAD */
1148         0x5b,		/* FC_END */
1149         0x8,		/* FC_LONG */
1150         0x8,		/* FC_LONG */
1151         0x8,		/* FC_LONG */
1152         0x5c,		/* FC_PAD */
1153         0x5b,		/* FC_END */
1154 #endif
1155     };
1156 
1157     /* zero the entire structure, including the holes */
1158     memset(&s1, 0, sizeof(s1));
1159 
1160     /* FC_STRUCT */
1161     s1.s = 0x1234;
1162     s1.c = 0xa5;
1163     s1.l1 = 0xdeadbeef;
1164     s1.l2 = 0xcafebabe;
1165     s1.ll = ((ULONGLONG) 0xbadefeed << 32) | 0x2468ace0;
1166 
1167     wiredatalen = 24;
1168     memcpy(wiredata, &s1, wiredatalen);
1169     test_simple_struct_marshal(fmtstr_simple_struct + 4, &s1, 24, wiredata, 24, NULL, 0, "struct");
1170 
1171     if (use_pointer_ids)
1172         *(unsigned int *)wiredata = 0x20000;
1173     else
1174         *(unsigned int *)wiredata = (UINT_PTR)&s1;
1175     memcpy(wiredata + 4, &s1, wiredatalen);
1176     test_pointer_marshal(fmtstr_simple_struct, &s1, 24, wiredata, 28, NULL, 0, "struct");
1177 
1178     if (sizeof(void *) == 8) return;  /* it cannot be represented as a simple struct on Win64 */
1179 
1180     /* zero the entire structure, including the hole */
1181     memset(&ps1, 0, sizeof(ps1));
1182 
1183     /* FC_PSTRUCT */
1184     ps1.l1 = 0xdeadbeef;
1185     l = 0xcafebabe;
1186     ps1.pl1 = &l;
1187     c = 'a';
1188     ps1.pc1 = &c;
1189     *(unsigned int *)(wiredata + 4) = 0xdeadbeef;
1190     if (use_pointer_ids)
1191     {
1192 	*(unsigned int *)(wiredata + 8) = 0x20000;
1193 	*(unsigned int *)(wiredata + 12) = 0x20004;
1194     }
1195     else
1196     {
1197 	*(unsigned int *)(wiredata + 8) = (UINT_PTR)&l;
1198 	*(unsigned int *)(wiredata + 12) = (UINT_PTR)&c;
1199     }
1200     memcpy(wiredata + 16, &l, 4);
1201     memcpy(wiredata + 20, &c, 1);
1202 
1203     test_simple_struct_marshal(fmtstr_pointer_struct + 4, &ps1, 17, wiredata + 4, 17, ps1_cmp, 2, "pointer_struct");
1204     if (use_pointer_ids)
1205     {
1206         *(unsigned int *)wiredata = 0x20000;
1207 	*(unsigned int *)(wiredata + 8) = 0x20004;
1208 	*(unsigned int *)(wiredata + 12) = 0x20008;
1209     }
1210     else
1211         *(unsigned int *)wiredata = (UINT_PTR)&ps1;
1212     test_pointer_marshal(fmtstr_pointer_struct, &ps1, 17, wiredata, 21, ps1_cmp, 2, "pointer_struct");
1213 }
1214 
1215 struct aligned
1216 {
1217     int a;
1218     LONGLONG b;
1219 };
1220 
1221 static void test_struct_align(void)
1222 {
1223     RPC_MESSAGE RpcMessage;
1224     MIDL_STUB_MESSAGE StubMsg;
1225     MIDL_STUB_DESC StubDesc;
1226     void *ptr;
1227     struct aligned *memsrc_orig, *memsrc, *mem;
1228 
1229     /* force bogus struct so that members are marshalled individually */
1230     static const unsigned char fmtstr[] =
1231     {
1232         0x1a,   /* FC_BOGUS_STRUCT */
1233         0x7,    /* alignment 8 */
1234         NdrFcShort(0x10),   /* memory size 16 */
1235         NdrFcShort(0x0),
1236         NdrFcShort(0x0),
1237         0x08,   /* FC_LONG */
1238         0x39,   /* FC_ALIGNM8 */
1239         0x0b,   /* FC_HYPER */
1240         0x5b,   /* FC_END */
1241     };
1242 
1243     memsrc_orig = heap_alloc_zero(sizeof(struct aligned) + 8);
1244     /* intentionally mis-align memsrc */
1245     memsrc = (struct aligned *)((((ULONG_PTR)memsrc_orig + 7) & ~7) + 4);
1246 
1247     memsrc->a = 0xdeadbeef;
1248     memsrc->b = ((ULONGLONG) 0xbadefeed << 32) | 0x2468ace0;
1249 
1250     StubDesc = Object_StubDesc;
1251     StubDesc.pFormatTypes = fmtstr;
1252     NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0);
1253 
1254     StubMsg.BufferLength = 0;
1255     NdrComplexStructBufferSize(&StubMsg, (unsigned char *)memsrc, fmtstr);
1256 
1257     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = heap_alloc(StubMsg.BufferLength);
1258     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
1259 
1260     ptr = NdrComplexStructMarshall(&StubMsg, (unsigned char *)memsrc, fmtstr);
1261     ok(ptr == NULL, "ret %p\n", ptr);
1262 
1263     /* Server */
1264     StubMsg.IsClient = 0;
1265     mem = NULL;
1266     StubMsg.Buffer = StubMsg.BufferStart;
1267     ptr = NdrComplexStructUnmarshall(&StubMsg, (unsigned char **)&mem, fmtstr, 0);
1268     ok(ptr == NULL, "ret %p\n", ptr);
1269     ok(!memcmp(mem, memsrc, sizeof(*memsrc)), "struct wasn't unmarshalled correctly\n");
1270     StubMsg.pfnFree(mem);
1271 
1272     heap_free(StubMsg.RpcMsg->Buffer);
1273     heap_free(memsrc_orig);
1274 }
1275 
1276 struct testiface
1277 {
1278     IPersist IPersist_iface;
1279     LONG ref;
1280 };
1281 
1282 static struct testiface *impl_from_IPersist(IPersist *iface)
1283 {
1284     return CONTAINING_RECORD(iface, struct testiface, IPersist_iface);
1285 }
1286 
1287 static HRESULT WINAPI test_persist_QueryInterface(IPersist *iface, REFIID iid, void **out)
1288 {
1289     if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IPersist))
1290     {
1291         *out = iface;
1292         IPersist_AddRef(iface);
1293         return S_OK;
1294     }
1295 
1296     *out = NULL;
1297     return E_NOINTERFACE;
1298 }
1299 
1300 static ULONG WINAPI test_persist_AddRef(IPersist *iface)
1301 {
1302     struct testiface *unk = impl_from_IPersist(iface);
1303     return ++unk->ref;
1304 }
1305 
1306 static ULONG WINAPI test_persist_Release(IPersist *iface)
1307 {
1308     struct testiface *unk = impl_from_IPersist(iface);
1309     return --unk->ref;
1310 }
1311 
1312 static HRESULT WINAPI test_persist_GetClassId(IPersist *iface, GUID *clsid)
1313 {
1314     *clsid = IID_IPersist;
1315     return S_OK;
1316 }
1317 
1318 static IPersistVtbl testiface_vtbl = {
1319     test_persist_QueryInterface,
1320     test_persist_AddRef,
1321     test_persist_Release,
1322     test_persist_GetClassId,
1323 };
1324 
1325 static void test_iface_ptr(void)
1326 {
1327     struct testiface server_obj = {{&testiface_vtbl}, 1};
1328     struct testiface client_obj = {{&testiface_vtbl}, 1};
1329 
1330     MIDL_STUB_MESSAGE StubMsg;
1331     MIDL_STUB_DESC StubDesc;
1332     RPC_MESSAGE RpcMessage;
1333     IPersist *proxy;
1334     HRESULT hr;
1335     GUID clsid;
1336     void *ptr;
1337     LONG ref;
1338 
1339     static const unsigned char fmtstr_ip[] =
1340     {
1341         FC_IP,
1342         FC_CONSTANT_IID,
1343         NdrFcLong(0x0000010c),
1344         NdrFcShort(0x0000),
1345         NdrFcShort(0x0000),
1346         0xc0,
1347         0x00,
1348         0x00,
1349         0x00,
1350         0x00,
1351         0x00,
1352         0x00,
1353         0x46,
1354     };
1355 
1356     CoInitialize(NULL);
1357 
1358     StubDesc = Object_StubDesc;
1359     StubDesc.pFormatTypes = fmtstr_ip;
1360 
1361     NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0);
1362     StubMsg.BufferLength = 0;
1363     NdrInterfacePointerBufferSize(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
1364 
1365     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
1366     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
1367 
1368     /* server -> client */
1369 
1370     StubMsg.IsClient = 0;
1371     my_alloc_called = my_free_called = 0;
1372     StubMsg.Buffer = StubMsg.BufferStart;
1373     IPersist_AddRef(&server_obj.IPersist_iface);
1374     ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
1375     ok(!ptr, "ret %p\n", ptr);
1376     ok(server_obj.ref > 2, "got %d references\n", server_obj.ref);
1377     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1378     ok(!my_free_called, "free called %d\n", my_free_called);
1379 
1380     NdrInterfacePointerFree(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
1381     ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
1382 
1383     StubMsg.IsClient = 1;
1384     my_alloc_called = my_free_called = 0;
1385     StubMsg.Buffer = StubMsg.BufferStart;
1386     proxy = NULL;
1387     ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
1388     ok(!ptr, "ret %p\n", ptr);
1389     ok(!!proxy, "mem not alloced\n");
1390     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1391     ok(!my_free_called, "free called %d\n", my_free_called);
1392     ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
1393 
1394     hr = IPersist_GetClassID(proxy, &clsid);
1395     ok(hr == S_OK, "got hr %#x\n", hr);
1396     ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
1397 
1398     ref = IPersist_Release(proxy);
1399     ok(ref == 1, "got %d references\n", ref);
1400     ok(server_obj.ref == 1, "got %d references\n", server_obj.ref);
1401 
1402     /* An existing interface pointer is released; this is necessary so that an
1403      * [in, out] pointer which changes does not leak references. */
1404 
1405     StubMsg.IsClient = 0;
1406     my_alloc_called = my_free_called = 0;
1407     StubMsg.Buffer = StubMsg.BufferStart;
1408     IPersist_AddRef(&server_obj.IPersist_iface);
1409     ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
1410     ok(!ptr, "ret %p\n", ptr);
1411     ok(server_obj.ref > 2, "got %d references\n", server_obj.ref);
1412     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1413     ok(!my_free_called, "free called %d\n", my_free_called);
1414 
1415     NdrInterfacePointerFree(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
1416     ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
1417 
1418     StubMsg.IsClient = 1;
1419     my_alloc_called = my_free_called = 0;
1420     StubMsg.Buffer = StubMsg.BufferStart;
1421     proxy = &client_obj.IPersist_iface;
1422     IPersist_AddRef(proxy);
1423     ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
1424     ok(!ptr, "ret %p\n", ptr);
1425     ok(!!proxy && proxy != &client_obj.IPersist_iface, "mem not alloced\n");
1426     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1427     ok(!my_free_called, "free called %d\n", my_free_called);
1428     ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
1429     ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
1430 
1431     hr = IPersist_GetClassID(proxy, &clsid);
1432     ok(hr == S_OK, "got hr %#x\n", hr);
1433     ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
1434 
1435     ref = IPersist_Release(proxy);
1436     ok(ref == 1, "got %d references\n", ref);
1437     ok(server_obj.ref == 1, "got %d references\n", server_obj.ref);
1438 
1439     /* client -> server */
1440 
1441     StubMsg.IsClient = 1;
1442     my_alloc_called = my_free_called = 0;
1443     StubMsg.Buffer = StubMsg.BufferStart;
1444     IPersist_AddRef(&client_obj.IPersist_iface);
1445     ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
1446     ok(!ptr, "ret %p\n", ptr);
1447     ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
1448     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1449     ok(!my_free_called, "free called %d\n", my_free_called);
1450 
1451     StubMsg.IsClient = 0;
1452     my_alloc_called = my_free_called = 0;
1453     StubMsg.Buffer = StubMsg.BufferStart;
1454     proxy = NULL;
1455     ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
1456     ok(!ptr, "ret %p\n", ptr);
1457     ok(!!proxy, "mem not alloced\n");
1458     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1459     ok(!my_free_called, "free called %d\n", my_free_called);
1460     ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
1461 
1462     hr = IPersist_GetClassID(proxy, &clsid);
1463     ok(hr == S_OK, "got hr %#x\n", hr);
1464     ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
1465 
1466     ref = IPersist_Release(proxy);
1467     ok(client_obj.ref > 1, "got %d references\n", client_obj.ref);
1468     ok(ref == client_obj.ref, "expected %d references, got %d\n", client_obj.ref, ref);
1469 
1470     NdrInterfacePointerFree(&StubMsg, (unsigned char *)proxy, fmtstr_ip);
1471     ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
1472 
1473     /* same, but free the interface after calling NdrInterfacePointerFree */
1474 
1475     StubMsg.IsClient = 1;
1476     my_alloc_called = my_free_called = 0;
1477     StubMsg.Buffer = StubMsg.BufferStart;
1478     IPersist_AddRef(&client_obj.IPersist_iface);
1479     ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
1480     ok(!ptr, "ret %p\n", ptr);
1481     ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
1482     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1483     ok(!my_free_called, "free called %d\n", my_free_called);
1484 
1485     StubMsg.IsClient = 0;
1486     my_alloc_called = my_free_called = 0;
1487     StubMsg.Buffer = StubMsg.BufferStart;
1488     proxy = NULL;
1489     ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
1490     ok(!ptr, "ret %p\n", ptr);
1491     ok(!!proxy, "mem not alloced\n");
1492     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1493     ok(!my_free_called, "free called %d\n", my_free_called);
1494     ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
1495 
1496     NdrInterfacePointerFree(&StubMsg, (unsigned char *)proxy, fmtstr_ip);
1497     ok(client_obj.ref > 1, "got %d references\n", client_obj.ref);
1498 
1499     hr = IPersist_GetClassID(proxy, &clsid);
1500     ok(hr == S_OK, "got hr %#x\n", hr);
1501     ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
1502 
1503     ref = IPersist_Release(proxy);
1504     ok(ref == 1, "got %d references\n", ref);
1505     ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
1506 
1507     /* An existing interface pointer is *not* released (in fact, it is ignored
1508      * and may be invalid). In practice it will always be NULL anyway. */
1509 
1510     StubMsg.IsClient = 1;
1511     my_alloc_called = my_free_called = 0;
1512     StubMsg.Buffer = StubMsg.BufferStart;
1513     IPersist_AddRef(&client_obj.IPersist_iface);
1514     ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
1515     ok(!ptr, "ret %p\n", ptr);
1516     ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
1517     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1518     ok(!my_free_called, "free called %d\n", my_free_called);
1519 
1520     StubMsg.IsClient = 0;
1521     my_alloc_called = my_free_called = 0;
1522     StubMsg.Buffer = StubMsg.BufferStart;
1523     proxy = &server_obj.IPersist_iface;
1524     IPersist_AddRef(proxy);
1525     ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
1526     ok(!ptr, "ret %p\n", ptr);
1527     ok(!!proxy && proxy != &server_obj.IPersist_iface, "mem not alloced\n");
1528     ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
1529     ok(!my_free_called, "free called %d\n", my_free_called);
1530     ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
1531     ok(server_obj.ref == 2, "got %d references\n", server_obj.ref);
1532     IPersist_Release(&server_obj.IPersist_iface);
1533 
1534     hr = IPersist_GetClassID(proxy, &clsid);
1535     ok(hr == S_OK, "got hr %#x\n", hr);
1536     ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
1537 
1538     ref = IPersist_Release(proxy);
1539     ok(client_obj.ref > 1, "got %d references\n", client_obj.ref);
1540     ok(ref == client_obj.ref, "expected %d references, got %d\n", client_obj.ref, ref);
1541 
1542     NdrInterfacePointerFree(&StubMsg, (unsigned char *)proxy, fmtstr_ip);
1543     ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
1544 
1545     HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart);
1546 
1547     CoUninitialize();
1548 }
1549 
1550 static void test_fullpointer_xlat(void)
1551 {
1552     PFULL_PTR_XLAT_TABLES pXlatTables;
1553     ULONG RefId;
1554     int ret;
1555     void *Pointer;
1556 
1557     pXlatTables = NdrFullPointerXlatInit(2, XLAT_CLIENT);
1558 
1559     /* "marshaling" phase */
1560 
1561     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 1, &RefId);
1562     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1563     ok(RefId == 0x1, "RefId should be 0x1 instead of 0x%x\n", RefId);
1564 
1565     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 0, &RefId);
1566     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1567     ok(RefId == 0x1, "RefId should be 0x1 instead of 0x%x\n", RefId);
1568 
1569     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebabe, 0, &RefId);
1570     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1571     ok(RefId == 0x2, "RefId should be 0x2 instead of 0x%x\n", RefId);
1572 
1573     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xdeadbeef, 0, &RefId);
1574     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1575     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%x\n", RefId);
1576 
1577     ret = NdrFullPointerQueryPointer(pXlatTables, NULL, 0, &RefId);
1578     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1579     ok(RefId == 0, "RefId should be 0 instead of 0x%x\n", RefId);
1580 
1581     /* "unmarshaling" phase */
1582 
1583     ret = NdrFullPointerQueryRefId(pXlatTables, 0x0, 0, &Pointer);
1584     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1585 
1586     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 0, &Pointer);
1587     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1588     ok(Pointer == (void *)0xcafebabe, "Pointer should be 0xcafebabe instead of %p\n", Pointer);
1589 
1590     ret = NdrFullPointerQueryRefId(pXlatTables, 0x4, 0, &Pointer);
1591     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1592     ok(Pointer == NULL, "Pointer should be NULL instead of %p\n", Pointer);
1593 
1594     NdrFullPointerInsertRefId(pXlatTables, 0x4, (void *)0xdeadbabe);
1595 
1596     ret = NdrFullPointerQueryRefId(pXlatTables, 0x4, 1, &Pointer);
1597     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1598     ok(Pointer == (void *)0xdeadbabe, "Pointer should be (void *)0xdeadbabe instead of %p\n", Pointer);
1599 
1600     NdrFullPointerXlatFree(pXlatTables);
1601 
1602     pXlatTables = NdrFullPointerXlatInit(2, XLAT_SERVER);
1603 
1604     /* "unmarshaling" phase */
1605 
1606     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 1, &Pointer);
1607     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1608     ok(Pointer == NULL, "Pointer should be NULL instead of %p\n", Pointer);
1609 
1610     NdrFullPointerInsertRefId(pXlatTables, 0x2, (void *)0xcafebabe);
1611 
1612     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 0, &Pointer);
1613     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1614     ok(Pointer == (void *)0xcafebabe, "Pointer should be (void *)0xcafebabe instead of %p\n", Pointer);
1615 
1616     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 1, &Pointer);
1617     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1618     ok(Pointer == (void *)0xcafebabe, "Pointer should be (void *)0xcafebabe instead of %p\n", Pointer);
1619 
1620     /* "marshaling" phase */
1621 
1622     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 1, &RefId);
1623     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1624     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%x\n", RefId);
1625 
1626     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 1, &RefId);
1627     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1628     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%x\n", RefId);
1629 
1630     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 0, &RefId);
1631     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1632     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%x\n", RefId);
1633 
1634     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebabe, 0, &RefId);
1635     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1636     ok(RefId == 0x2, "RefId should be 0x2 instead of 0x%x\n", RefId);
1637 
1638     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xdeadbeef, 0, &RefId);
1639     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1640     ok(RefId == 0x4, "RefId should be 0x4 instead of 0x%x\n", RefId);
1641 
1642     /* "freeing" phase */
1643 
1644     ret = NdrFullPointerFree(pXlatTables, (void *)0xcafebeef);
1645     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1646 
1647     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 0x20, &RefId);
1648     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1649     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%x\n", RefId);
1650 
1651     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 1, &RefId);
1652     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1653     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%x\n", RefId);
1654 
1655     ret = NdrFullPointerFree(pXlatTables, (void *)0xcafebabe);
1656     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1657 
1658     ret = NdrFullPointerFree(pXlatTables, (void *)0xdeadbeef);
1659     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1660 
1661     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xdeadbeef, 0x20, &RefId);
1662     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1663     ok(RefId == 0x4, "RefId should be 0x4 instead of 0x%x\n", RefId);
1664 
1665     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xdeadbeef, 1, &RefId);
1666     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1667     ok(RefId == 0x4, "RefId should be 0x4 instead of 0x%x\n", RefId);
1668 
1669     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xdeadbeef, 1, &RefId);
1670     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
1671     ok(RefId == 0x4, "RefId should be 0x4 instead of 0x%x\n", RefId);
1672 
1673     ret = NdrFullPointerFree(pXlatTables, (void *)0xdeadbeef);
1674     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
1675 
1676     NdrFullPointerXlatFree(pXlatTables);
1677 }
1678 
1679 /* verify stub data that is identical between client and server */
1680 static void test_common_stub_data( const char *prefix, const MIDL_STUB_MESSAGE *stubMsg )
1681 {
1682     void *unset_ptr;
1683 
1684     memset(&unset_ptr, 0xcc, sizeof(unset_ptr));
1685 
1686 #define TEST_ZERO(field, fmt) ok(stubMsg->field == 0, "%s: " #field " should have been set to zero instead of " fmt "\n", prefix, stubMsg->field)
1687 #define TEST_POINTER_UNSET(field) ok(stubMsg->field == unset_ptr, "%s: " #field " should have been unset instead of %p\n", prefix, stubMsg->field)
1688 #define TEST_ULONG_UNSET(field) ok(stubMsg->field == 0xcccccccc, "%s: " #field " should have been unset instead of 0x%x\n", prefix, stubMsg->field)
1689 #define TEST_ULONG_PTR_UNSET(field) ok(stubMsg->field == (ULONG_PTR)unset_ptr, "%s: " #field " should have been unset instead of 0x%lx\n", prefix, stubMsg->field)
1690 
1691     TEST_POINTER_UNSET(BufferMark);
1692     TEST_ULONG_UNSET(MemorySize);
1693     TEST_POINTER_UNSET(Memory);
1694     TEST_ZERO(pAllocAllNodesContext, "%p");
1695     ok(stubMsg->pPointerQueueState == 0 ||
1696        broken(stubMsg->pPointerQueueState == unset_ptr), /* win2k */
1697        "%s: pPointerQueueState should have been unset instead of %p\n",
1698        prefix, stubMsg->pPointerQueueState);
1699     TEST_ZERO(IgnoreEmbeddedPointers, "%d");
1700     TEST_ZERO(PointerBufferMark, "%p");
1701     ok( stubMsg->uFlags == 0 ||
1702         broken(stubMsg->uFlags == 0xcc), /* win9x */
1703         "%s: uFlags should have been set to zero instead of 0x%x\n", prefix, stubMsg->uFlags );
1704     /* FIXME: UniquePtrCount */
1705     TEST_ULONG_PTR_UNSET(MaxCount);
1706     TEST_ULONG_UNSET(Offset);
1707     TEST_ULONG_UNSET(ActualCount);
1708     ok(stubMsg->pfnAllocate == my_alloc, "%s: pfnAllocate should have been %p instead of %p\n",
1709        prefix, my_alloc, stubMsg->pfnAllocate);
1710     ok(stubMsg->pfnFree == my_free, "%s: pfnFree should have been %p instead of %p\n",
1711        prefix, my_free, stubMsg->pfnFree);
1712     TEST_ZERO(StackTop, "%p");
1713     TEST_POINTER_UNSET(pPresentedType);
1714     TEST_POINTER_UNSET(pTransmitType);
1715     TEST_POINTER_UNSET(SavedHandle);
1716     ok(stubMsg->StubDesc == &Object_StubDesc, "%s: StubDesc should have been %p instead of %p\n",
1717        prefix, &Object_StubDesc, stubMsg->StubDesc);
1718     TEST_ZERO(FullPtrRefId, "%d");
1719     ok( stubMsg->PointerLength == 0 ||
1720         broken(stubMsg->PointerLength == 1), /* win9x, nt4 */
1721         "%s: pAsyncMsg should have been set to zero instead of %d\n", prefix, stubMsg->PointerLength );
1722     TEST_ZERO(fInDontFree, "%d");
1723     TEST_ZERO(fDontCallFreeInst, "%d");
1724     ok( stubMsg->fHasReturn == 0 || broken(stubMsg->fHasReturn), /* win9x, nt4 */
1725         "%s: fHasReturn should have been set to zero instead of %d\n", prefix, stubMsg->fHasReturn );
1726     TEST_ZERO(fHasExtensions, "%d");
1727     TEST_ZERO(fHasNewCorrDesc, "%d");
1728     ok(stubMsg->fIsIn == 0 || broken(stubMsg->fIsIn), /* win9x, nt4 */
1729        "%s: fIsIn should have been set to 0 instead of %d\n", prefix, stubMsg->fIsIn);
1730     TEST_ZERO(fIsOicf, "%d");
1731     ok(stubMsg->fBufferValid == 0,
1732        "%s: fBufferValid should have been set to 0 instead of %d\n", prefix, stubMsg->fBufferValid);
1733     TEST_ZERO(fNeedMCCP, "%d");
1734     ok(stubMsg->fUnused == 0 ||
1735        stubMsg->fUnused == -2, /* Vista */
1736        "%s: fUnused should have been set to 0 or -2 instead of %d\n", prefix, stubMsg->fUnused);
1737     ok(stubMsg->fUnused2 == 0xffffcccc, "%s: fUnused2 should have been 0xffffcccc instead of 0x%x\n",
1738        prefix, stubMsg->fUnused2);
1739     ok(stubMsg->dwDestContext == MSHCTX_DIFFERENTMACHINE,
1740        "%s: dwDestContext should have been MSHCTX_DIFFERENTMACHINE instead of %d\n",
1741        prefix, stubMsg->dwDestContext);
1742     TEST_ZERO(pvDestContext, "%p");
1743     TEST_POINTER_UNSET(SavedContextHandles);
1744     TEST_ULONG_UNSET(ParamNumber);
1745     TEST_ZERO(pRpcChannelBuffer, "%p");
1746     TEST_ZERO(pArrayInfo, "%p");
1747     TEST_POINTER_UNSET(SizePtrCountArray);
1748     TEST_POINTER_UNSET(SizePtrOffsetArray);
1749     TEST_POINTER_UNSET(SizePtrLengthArray);
1750     TEST_POINTER_UNSET(pArgQueue);
1751     TEST_ZERO(dwStubPhase, "%d");
1752     /* FIXME: where does this value come from? */
1753     trace("%s: LowStackMark is %p\n", prefix, stubMsg->LowStackMark);
1754     ok( stubMsg->pAsyncMsg == 0 || broken(stubMsg->pAsyncMsg == unset_ptr), /* win9x, nt4 */
1755         "%s: pAsyncMsg should have been set to zero instead of %p\n", prefix, stubMsg->pAsyncMsg );
1756     ok( stubMsg->pCorrInfo == 0 || broken(stubMsg->pCorrInfo == unset_ptr), /* win9x, nt4 */
1757         "%s: pCorrInfo should have been set to zero instead of %p\n", prefix, stubMsg->pCorrInfo );
1758     ok( stubMsg->pCorrMemory == 0 || broken(stubMsg->pCorrMemory == unset_ptr), /* win9x, nt4 */
1759         "%s: pCorrMemory should have been set to zero instead of %p\n", prefix, stubMsg->pCorrMemory );
1760     ok( stubMsg->pMemoryList == 0 || broken(stubMsg->pMemoryList == unset_ptr), /* win9x, nt4 */
1761         "%s: pMemoryList should have been set to zero instead of %p\n", prefix, stubMsg->pMemoryList );
1762     TEST_POINTER_UNSET(pCSInfo);
1763     TEST_POINTER_UNSET(ConformanceMark);
1764     TEST_POINTER_UNSET(VarianceMark);
1765     ok(stubMsg->Unused == (ULONG_PTR)unset_ptr, "%s: Unused should have be unset instead of 0x%lx\n",
1766        prefix, stubMsg->Unused);
1767     TEST_POINTER_UNSET(pContext);
1768     TEST_POINTER_UNSET(ContextHandleHash);
1769     TEST_POINTER_UNSET(pUserMarshalList);
1770     TEST_ULONG_PTR_UNSET(Reserved51_3);
1771     TEST_ULONG_PTR_UNSET(Reserved51_4);
1772     TEST_ULONG_PTR_UNSET(Reserved51_5);
1773 
1774 #undef TEST_ULONG_PTR_UNSET
1775 #undef TEST_ULONG_UNSET
1776 #undef TEST_POINTER_UNSET
1777 #undef TEST_ZERO
1778 }
1779 
1780 static void test_client_init(void)
1781 {
1782     MIDL_STUB_MESSAGE stubMsg;
1783     RPC_MESSAGE rpcMsg;
1784     void *unset_ptr;
1785 
1786     memset(&rpcMsg, 0xcc, sizeof(rpcMsg));
1787     memset(&stubMsg, 0xcc, sizeof(stubMsg));
1788     memset(&unset_ptr, 0xcc, sizeof(unset_ptr));
1789 
1790     NdrClientInitializeNew(&rpcMsg, &stubMsg, &Object_StubDesc, 1);
1791 
1792     test_common_stub_data( "NdrClientInitializeNew", &stubMsg );
1793 
1794     ok(stubMsg.RpcMsg == &rpcMsg, "stubMsg.RpcMsg should have been %p instead of %p\n", &rpcMsg, stubMsg.RpcMsg);
1795     ok(rpcMsg.Handle == NULL, "rpcMsg.Handle should have been NULL instead of %p\n", rpcMsg.Handle);
1796     ok(rpcMsg.Buffer == unset_ptr, "rpcMsg.Buffer should have been unset instead of %p\n",
1797        rpcMsg.Buffer);
1798     ok(rpcMsg.BufferLength == 0xcccccccc, "rpcMsg.BufferLength should have been unset instead of %d\n", rpcMsg.BufferLength);
1799     ok(rpcMsg.ProcNum == 0x8001, "rpcMsg.ProcNum should have been 0x8001 instead of 0x%x\n", rpcMsg.ProcNum);
1800     ok(rpcMsg.TransferSyntax == unset_ptr, "rpcMsg.TransferSyntax should have been unset instead of %p\n", rpcMsg.TransferSyntax);
1801     ok(rpcMsg.RpcInterfaceInformation == Object_StubDesc.RpcInterfaceInformation,
1802         "rpcMsg.RpcInterfaceInformation should have been %p instead of %p\n",
1803         Object_StubDesc.RpcInterfaceInformation, rpcMsg.RpcInterfaceInformation);
1804     /* Note: ReservedForRuntime not tested */
1805     ok(rpcMsg.ManagerEpv == unset_ptr, "rpcMsg.ManagerEpv should have been unset instead of %p\n", rpcMsg.ManagerEpv);
1806     ok(rpcMsg.ImportContext == unset_ptr, "rpcMsg.ImportContext should have been unset instead of %p\n", rpcMsg.ImportContext);
1807     ok(rpcMsg.RpcFlags == 0, "rpcMsg.RpcFlags should have been 0 instead of 0x%x\n", rpcMsg.RpcFlags);
1808 
1809     ok(stubMsg.Buffer == unset_ptr, "stubMsg.Buffer should have been unset instead of %p\n",
1810        stubMsg.Buffer);
1811     ok(stubMsg.BufferStart == NULL, "stubMsg.BufferStart should have been NULL instead of %p\n",
1812        stubMsg.BufferStart);
1813     ok(stubMsg.BufferEnd == NULL, "stubMsg.BufferEnd should have been NULL instead of %p\n",
1814        stubMsg.BufferEnd);
1815     ok(stubMsg.BufferLength == 0, "stubMsg.BufferLength should have been 0 instead of %u\n",
1816        stubMsg.BufferLength);
1817     ok(stubMsg.IsClient == 1, "stubMsg.IsClient should have been 1 instead of %u\n", stubMsg.IsClient);
1818     ok(stubMsg.ReuseBuffer == 0, "stubMsg.ReuseBuffer should have been 0 instead of %d\n",
1819        stubMsg.ReuseBuffer);
1820     ok(stubMsg.CorrDespIncrement == 0, "stubMsg.CorrDespIncrement should have been 0 instead of %d\n",
1821        stubMsg.CorrDespIncrement);
1822     ok(stubMsg.FullPtrXlatTables == unset_ptr, "stubMsg.FullPtrXlatTables should have been unset instead of %p\n",
1823        stubMsg.FullPtrXlatTables);
1824 }
1825 
1826 static void test_server_init(void)
1827 {
1828     MIDL_STUB_MESSAGE stubMsg;
1829     RPC_MESSAGE rpcMsg;
1830     unsigned char *ret;
1831     unsigned char buffer[256];
1832 
1833     memset(&rpcMsg, 0, sizeof(rpcMsg));
1834     rpcMsg.Buffer = buffer;
1835     rpcMsg.BufferLength = sizeof(buffer);
1836     rpcMsg.RpcFlags = RPC_BUFFER_COMPLETE;
1837 
1838     memset(&stubMsg, 0xcc, sizeof(stubMsg));
1839 
1840     ret = NdrServerInitializeNew(&rpcMsg, &stubMsg, &Object_StubDesc);
1841     ok(ret == NULL, "NdrServerInitializeNew should have returned NULL instead of %p\n", ret);
1842 
1843     test_common_stub_data( "NdrServerInitializeNew", &stubMsg );
1844 
1845     ok(stubMsg.RpcMsg == &rpcMsg, "stubMsg.RpcMsg should have been %p instead of %p\n", &rpcMsg, stubMsg.RpcMsg);
1846     ok(stubMsg.Buffer == buffer, "stubMsg.Buffer should have been %p instead of %p\n", buffer, stubMsg.Buffer);
1847     ok(stubMsg.BufferStart == buffer, "stubMsg.BufferStart should have been %p instead of %p\n", buffer, stubMsg.BufferStart);
1848     ok(stubMsg.BufferEnd == buffer + sizeof(buffer), "stubMsg.BufferEnd should have been %p instead of %p\n", buffer + sizeof(buffer), stubMsg.BufferEnd);
1849 todo_wine
1850     ok(stubMsg.BufferLength == 0, "stubMsg.BufferLength should have been 0 instead of %u\n", stubMsg.BufferLength);
1851     ok(stubMsg.IsClient == 0, "stubMsg.IsClient should have been 0 instead of %u\n", stubMsg.IsClient);
1852     ok(stubMsg.ReuseBuffer == 0 ||
1853        broken(stubMsg.ReuseBuffer == 1), /* win2k */
1854        "stubMsg.ReuseBuffer should have been set to zero instead of %d\n", stubMsg.ReuseBuffer);
1855     ok(stubMsg.CorrDespIncrement == 0 ||
1856        broken(stubMsg.CorrDespIncrement == 0xcc), /* <= Win 2003 */
1857        "CorrDespIncrement should have been set to zero instead of 0x%x\n", stubMsg.CorrDespIncrement);
1858     ok(stubMsg.FullPtrXlatTables == 0, "stubMsg.BufferLength should have been 0 instead of %p\n", stubMsg.FullPtrXlatTables);
1859 }
1860 
1861 static void test_ndr_allocate(void)
1862 {
1863     RPC_MESSAGE RpcMessage;
1864     MIDL_STUB_MESSAGE StubMsg;
1865     MIDL_STUB_DESC StubDesc;
1866     void *p1, *p2;
1867     struct tag_mem_list_v2_t
1868     {
1869         DWORD magic;
1870         DWORD size;
1871         DWORD unknown;
1872         struct tag_mem_list_v2_t *next;
1873     } *mem_list_v2;
1874     const DWORD magic_MEML = 'M' << 24 | 'E' << 16 | 'M' << 8 | 'L';
1875 
1876     StubDesc = Object_StubDesc;
1877     NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0);
1878 
1879     my_alloc_called = my_free_called = 0;
1880     p1 = NdrAllocate(&StubMsg, 10);
1881     p2 = NdrAllocate(&StubMsg, 24);
1882     ok(my_alloc_called == 2, "alloc called %d\n", my_alloc_called);
1883     ok(StubMsg.pMemoryList != NULL, "StubMsg.pMemoryList NULL\n");
1884     if(StubMsg.pMemoryList)
1885     {
1886         mem_list_v2 = StubMsg.pMemoryList;
1887         if (mem_list_v2->size == 24)
1888         {
1889             trace("v2 mem list format\n");
1890             ok((char *)mem_list_v2 == (char *)p2 + 24, "expected mem_list_v2 pointer %p, but got %p\n", (char *)p2 + 24, mem_list_v2);
1891             ok(mem_list_v2->magic == magic_MEML, "magic %08x\n", mem_list_v2->magic);
1892             ok(mem_list_v2->size == 24, "wrong size for p2 %d\n", mem_list_v2->size);
1893             ok(mem_list_v2->unknown == 0, "wrong unknown for p2 0x%x\n", mem_list_v2->unknown);
1894             ok(mem_list_v2->next != NULL, "next NULL\n");
1895             mem_list_v2 = mem_list_v2->next;
1896             if(mem_list_v2)
1897             {
1898                 ok((char *)mem_list_v2 == (char *)p1 + 16, "expected mem_list_v2 pointer %p, but got %p\n", (char *)p1 + 16, mem_list_v2);
1899                 ok(mem_list_v2->magic == magic_MEML, "magic %08x\n", mem_list_v2->magic);
1900                 ok(mem_list_v2->size == 16, "wrong size for p1 %d\n", mem_list_v2->size);
1901                 ok(mem_list_v2->unknown == 0, "wrong unknown for p1 0x%x\n", mem_list_v2->unknown);
1902                 ok(mem_list_v2->next == NULL, "next %p\n", mem_list_v2->next);
1903             }
1904         }
1905         else win_skip("v1 mem list format\n");
1906     }
1907     /* NdrFree isn't exported so we can't test free'ing */
1908     my_free(p1);
1909     my_free(p2);
1910 }
1911 
1912 static void test_conformant_array(void)
1913 {
1914     RPC_MESSAGE RpcMessage;
1915     MIDL_STUB_MESSAGE StubMsg;
1916     MIDL_STUB_DESC StubDesc;
1917     void *ptr;
1918     unsigned char *mem, *mem_orig;
1919     unsigned char memsrc[20];
1920     unsigned int i;
1921 
1922     static const unsigned char fmtstr_conf_array[] =
1923     {
1924         0x1b,              /* FC_CARRAY */
1925         0x0,               /* align */
1926         NdrFcShort( 0x1 ), /* elem size */
1927         0x40,              /* Corr desc:  const */
1928         0x0,
1929         NdrFcShort(0x10),  /* const = 0x10 */
1930         0x1,               /* FC_BYTE */
1931         0x5b               /* FC_END */
1932     };
1933 
1934     for (i = 0; i < sizeof(memsrc); i++)
1935         memsrc[i] = i * i;
1936 
1937     StubDesc = Object_StubDesc;
1938     StubDesc.pFormatTypes = fmtstr_conf_array;
1939 
1940     NdrClientInitializeNew(
1941                            &RpcMessage,
1942                            &StubMsg,
1943                            &StubDesc,
1944                            0);
1945 
1946     StubMsg.BufferLength = 0;
1947     NdrConformantArrayBufferSize( &StubMsg,
1948                           memsrc,
1949                           fmtstr_conf_array );
1950     ok(StubMsg.BufferLength >= 20, "length %d\n", StubMsg.BufferLength);
1951 
1952     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
1953     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
1954     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
1955 
1956     ptr = NdrConformantArrayMarshall( &StubMsg,  memsrc, fmtstr_conf_array );
1957     ok(ptr == NULL, "ret %p\n", ptr);
1958     ok(StubMsg.Buffer - StubMsg.BufferStart == 20, "Buffer %p Start %p len %d\n", StubMsg.Buffer, StubMsg.BufferStart, 20);
1959     ok(!memcmp(StubMsg.BufferStart + 4, memsrc, 16), "incorrectly marshaled\n");
1960 
1961     StubMsg.Buffer = StubMsg.BufferStart;
1962     StubMsg.MemorySize = 0;
1963     mem = NULL;
1964 
1965     /* Client */
1966     my_alloc_called = 0;
1967     /* passing mem == NULL with must_alloc == 0 crashes under Windows */
1968     NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 1);
1969     ok(mem != NULL, "mem not alloced\n");
1970     ok(mem != StubMsg.BufferStart + 4, "mem pointing at buffer\n");
1971     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
1972 
1973     my_alloc_called = 0;
1974     StubMsg.Buffer = StubMsg.BufferStart;
1975     mem_orig = mem;
1976     NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 0);
1977     ok(mem == mem_orig, "mem alloced\n");
1978     ok(mem != StubMsg.BufferStart + 4, "mem pointing at buffer\n");
1979     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
1980 
1981     my_alloc_called = 0;
1982     StubMsg.Buffer = StubMsg.BufferStart;
1983     NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 1);
1984     ok(mem != mem_orig, "mem not alloced\n");
1985     ok(mem != StubMsg.BufferStart + 4, "mem pointing at buffer\n");
1986     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
1987 
1988     my_free_called = 0;
1989     StubMsg.Buffer = StubMsg.BufferStart;
1990     NdrConformantArrayFree( &StubMsg, mem, fmtstr_conf_array );
1991     ok(my_free_called == 0, "free called %d\n", my_free_called);
1992     StubMsg.pfnFree(mem);
1993 
1994     /* Server */
1995     my_alloc_called = 0;
1996     StubMsg.IsClient = 0;
1997     mem = NULL;
1998     StubMsg.Buffer = StubMsg.BufferStart;
1999     NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 0);
2000     ok(mem == StubMsg.BufferStart + 4 || broken(!mem),  /* win9x, nt4 */
2001        "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 4);
2002     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2003     my_alloc_called = 0;
2004     mem = NULL;
2005     StubMsg.Buffer = StubMsg.BufferStart;
2006     NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 1);
2007     ok(mem != StubMsg.BufferStart + 4, "mem pointing at buffer\n");
2008     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
2009     StubMsg.pfnFree(mem);
2010 
2011     my_alloc_called = 0;
2012     mem = mem_orig;
2013     StubMsg.Buffer = StubMsg.BufferStart;
2014     NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 0);
2015     ok(mem == mem_orig, "mem alloced\n");
2016     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2017 
2018     my_alloc_called = 0;
2019     mem = mem_orig;
2020     StubMsg.Buffer = StubMsg.BufferStart;
2021     NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 1);
2022     ok(mem != StubMsg.BufferStart + 4, "mem pointing at buffer\n");
2023     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
2024     StubMsg.pfnFree(mem);
2025     StubMsg.pfnFree(mem_orig);
2026 
2027     HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer);
2028 }
2029 
2030 static void test_conformant_string(void)
2031 {
2032     RPC_MESSAGE RpcMessage;
2033     MIDL_STUB_MESSAGE StubMsg;
2034     MIDL_STUB_DESC StubDesc;
2035     DWORD size;
2036     void *ptr;
2037     unsigned char *mem, *mem_orig;
2038     char memsrc[] = "This is a test string";
2039 
2040     static const unsigned char fmtstr_conf_str[] =
2041     {
2042 			0x11, 0x8,	/* FC_RP [simple_pointer] */
2043 			0x22,		/* FC_C_CSTRING */
2044 			0x5c,		/* FC_PAD */
2045     };
2046 
2047     StubDesc = Object_StubDesc;
2048     StubDesc.pFormatTypes = fmtstr_conf_str;
2049 
2050     memset( &StubMsg, 0, sizeof(StubMsg) );  /* needed on win9x and nt4 */
2051     NdrClientInitializeNew(
2052                            &RpcMessage,
2053                            &StubMsg,
2054                            &StubDesc,
2055                            0);
2056 
2057     StubMsg.BufferLength = 0;
2058     NdrPointerBufferSize( &StubMsg,
2059                           (unsigned char *)memsrc,
2060                           fmtstr_conf_str );
2061     ok(StubMsg.BufferLength >= sizeof(memsrc) + 12, "length %d\n", StubMsg.BufferLength);
2062 
2063     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
2064     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
2065     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
2066 
2067     ptr = NdrPointerMarshall( &StubMsg, (unsigned char *)memsrc, fmtstr_conf_str );
2068     ok(ptr == NULL, "ret %p\n", ptr);
2069     size = StubMsg.Buffer - StubMsg.BufferStart;
2070     ok(size == sizeof(memsrc) + 12, "Buffer %p Start %p len %d\n",
2071        StubMsg.Buffer, StubMsg.BufferStart, size);
2072     ok(!memcmp(StubMsg.BufferStart + 12, memsrc, sizeof(memsrc)), "incorrectly marshaled\n");
2073 
2074     StubMsg.Buffer = StubMsg.BufferStart;
2075     StubMsg.MemorySize = 0;
2076     mem = NULL;
2077 
2078     /* Client */
2079     my_alloc_called = 0;
2080     StubMsg.Buffer = StubMsg.BufferStart;
2081     mem = mem_orig = HeapAlloc(GetProcessHeap(), 0, sizeof(memsrc));
2082     /* Windows apparently checks string length on the output buffer to determine its size... */
2083     memset( mem, 'x', sizeof(memsrc) - 1 );
2084     mem[sizeof(memsrc) - 1] = 0;
2085     NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 0);
2086     ok(mem == mem_orig, "mem not alloced\n");
2087     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2088 
2089     my_alloc_called = 0;
2090     StubMsg.Buffer = StubMsg.BufferStart;
2091     NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 1);
2092     ok(mem == mem_orig, "mem not alloced\n");
2093     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2094 
2095     /* Prevent a memory leak when running with Wine.
2096        Remove once the todo_wine block above is fixed. */
2097     if (mem != mem_orig)
2098         HeapFree(GetProcessHeap(), 0, mem_orig);
2099 
2100     my_free_called = 0;
2101     StubMsg.Buffer = StubMsg.BufferStart;
2102     NdrPointerFree( &StubMsg, mem, fmtstr_conf_str );
2103     ok(my_free_called == 1, "free called %d\n", my_free_called);
2104 
2105     mem = my_alloc(10);
2106     my_free_called = 0;
2107     StubMsg.Buffer = StubMsg.BufferStart;
2108     NdrPointerFree( &StubMsg, mem, fmtstr_conf_str );
2109     ok(my_free_called == 1, "free called %d\n", my_free_called);
2110 
2111     /* Server */
2112     my_alloc_called = 0;
2113     StubMsg.IsClient = 0;
2114     mem = NULL;
2115     StubMsg.Buffer = StubMsg.BufferStart;
2116     NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 0);
2117     ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */
2118        "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 );
2119     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2120 
2121     my_alloc_called = 0;
2122     mem = NULL;
2123     StubMsg.Buffer = StubMsg.BufferStart;
2124     NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 1);
2125     ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */
2126        "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 );
2127     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2128 
2129     my_alloc_called = 0;
2130     mem = mem_orig = HeapAlloc(GetProcessHeap(), 0, sizeof(memsrc));
2131     StubMsg.Buffer = StubMsg.BufferStart;
2132     NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 0);
2133     ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */
2134        "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 );
2135     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2136 
2137     my_alloc_called = 0;
2138     mem = mem_orig;
2139     StubMsg.Buffer = StubMsg.BufferStart;
2140     NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 1);
2141     ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */
2142        "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 );
2143     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2144 
2145     mem = my_alloc(10);
2146     my_free_called = 0;
2147     StubMsg.Buffer = StubMsg.BufferStart;
2148     NdrPointerFree( &StubMsg, mem, fmtstr_conf_str );
2149     ok(my_free_called == 1, "free called %d\n", my_free_called);
2150 
2151     HeapFree(GetProcessHeap(), 0, mem_orig);
2152     HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer);
2153 }
2154 
2155 static void test_nonconformant_string(void)
2156 {
2157     RPC_MESSAGE RpcMessage;
2158     MIDL_STUB_MESSAGE StubMsg;
2159     MIDL_STUB_DESC StubDesc;
2160     DWORD size;
2161     void *ptr;
2162     unsigned char *mem, *mem_orig;
2163     unsigned char memsrc[10] = "This is";
2164     unsigned char memsrc2[10] = "This is a";
2165 
2166     static const unsigned char fmtstr_nonconf_str[] =
2167     {
2168 			0x26,		/* FC_CSTRING */
2169 			0x5c,		/* FC_PAD */
2170 			NdrFcShort( 0xa ),	/* 10 */
2171     };
2172 
2173     StubDesc = Object_StubDesc;
2174     StubDesc.pFormatTypes = fmtstr_nonconf_str;
2175 
2176     /* length < size */
2177     NdrClientInitializeNew(
2178                            &RpcMessage,
2179                            &StubMsg,
2180                            &StubDesc,
2181                            0);
2182 
2183     StubMsg.BufferLength = 0;
2184 
2185     NdrNonConformantStringBufferSize( &StubMsg, memsrc, fmtstr_nonconf_str );
2186     ok(StubMsg.BufferLength >= strlen((char *)memsrc) + 1 + 8, "length %d\n", StubMsg.BufferLength);
2187 
2188     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
2189     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
2190     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
2191 
2192     ptr = NdrNonConformantStringMarshall( &StubMsg, memsrc, fmtstr_nonconf_str );
2193     ok(ptr == NULL, "ret %p\n", ptr);
2194     size = StubMsg.Buffer - StubMsg.BufferStart;
2195     ok(size == strlen((char *)memsrc) + 1 + 8, "Buffer %p Start %p len %d\n",
2196        StubMsg.Buffer, StubMsg.BufferStart, size);
2197     ok(!memcmp(StubMsg.BufferStart + 8, memsrc, strlen((char *)memsrc) + 1), "incorrectly marshaled\n");
2198 
2199     StubMsg.Buffer = StubMsg.BufferStart;
2200     StubMsg.MemorySize = 0;
2201     mem = NULL;
2202 
2203     /* Client */
2204     my_alloc_called = 0;
2205     StubMsg.Buffer = StubMsg.BufferStart;
2206     mem = mem_orig = HeapAlloc(GetProcessHeap(), 0, sizeof(memsrc));
2207     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 0);
2208     ok(mem == mem_orig, "mem alloced\n");
2209     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2210 
2211     my_alloc_called = 0;
2212     StubMsg.Buffer = StubMsg.BufferStart;
2213     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 1);
2214     todo_wine
2215     ok(mem == mem_orig, "mem alloced\n");
2216     todo_wine
2217     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2218 
2219     /* Server */
2220     my_alloc_called = 0;
2221     StubMsg.IsClient = 0;
2222     mem = NULL;
2223     StubMsg.Buffer = StubMsg.BufferStart;
2224     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 0);
2225     ok(mem != mem_orig, "mem not alloced\n");
2226     ok(mem != StubMsg.BufferStart + 8, "mem pointing at buffer\n");
2227     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
2228     NdrOleFree(mem);
2229 
2230     my_alloc_called = 0;
2231     mem = mem_orig;
2232     StubMsg.Buffer = StubMsg.BufferStart;
2233     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 0);
2234     ok(mem == mem_orig, "mem alloced\n");
2235     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2236 
2237     my_alloc_called = 0;
2238     mem = mem_orig;
2239     StubMsg.Buffer = StubMsg.BufferStart;
2240     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 1);
2241     todo_wine
2242     ok(mem == mem_orig, "mem alloced\n");
2243     todo_wine
2244     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2245 
2246     HeapFree(GetProcessHeap(), 0, mem_orig);
2247     HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer);
2248 
2249     /* length = size */
2250     NdrClientInitializeNew(
2251                            &RpcMessage,
2252                            &StubMsg,
2253                            &StubDesc,
2254                            0);
2255 
2256     StubMsg.BufferLength = 0;
2257 
2258     NdrNonConformantStringBufferSize( &StubMsg, memsrc2, fmtstr_nonconf_str );
2259     ok(StubMsg.BufferLength >= strlen((char *)memsrc2) + 1 + 8, "length %d\n", StubMsg.BufferLength);
2260 
2261     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
2262     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
2263     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
2264 
2265     ptr = NdrNonConformantStringMarshall( &StubMsg, memsrc2, fmtstr_nonconf_str );
2266     ok(ptr == NULL, "ret %p\n", ptr);
2267     size = StubMsg.Buffer - StubMsg.BufferStart;
2268     ok(size == strlen((char *)memsrc2) + 1 + 8, "Buffer %p Start %p len %d\n",
2269        StubMsg.Buffer, StubMsg.BufferStart, size);
2270     ok(!memcmp(StubMsg.BufferStart + 8, memsrc2, strlen((char *)memsrc2) + 1), "incorrectly marshaled\n");
2271 
2272     StubMsg.Buffer = StubMsg.BufferStart;
2273     StubMsg.MemorySize = 0;
2274     mem = NULL;
2275 
2276     /* Client */
2277     my_alloc_called = 0;
2278     StubMsg.Buffer = StubMsg.BufferStart;
2279     mem = mem_orig = HeapAlloc(GetProcessHeap(), 0, sizeof(memsrc));
2280     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 0);
2281     ok(mem == mem_orig, "mem alloced\n");
2282     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2283 
2284     my_alloc_called = 0;
2285     StubMsg.Buffer = StubMsg.BufferStart;
2286     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 1);
2287     todo_wine
2288     ok(mem == mem_orig, "mem alloced\n");
2289     todo_wine
2290     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2291 
2292     /* Server */
2293     my_alloc_called = 0;
2294     StubMsg.IsClient = 0;
2295     mem = NULL;
2296     StubMsg.Buffer = StubMsg.BufferStart;
2297     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 0);
2298     ok(mem != mem_orig, "mem not alloced\n");
2299     ok(mem != StubMsg.BufferStart + 8, "mem pointing at buffer\n");
2300     ok(my_alloc_called == 1, "alloc called %d\n", my_alloc_called);
2301     NdrOleFree(mem);
2302 
2303     my_alloc_called = 0;
2304     mem = mem_orig;
2305     StubMsg.Buffer = StubMsg.BufferStart;
2306     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 0);
2307     ok(mem == mem_orig, "mem alloced\n");
2308     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2309 
2310     my_alloc_called = 0;
2311     mem = mem_orig;
2312     StubMsg.Buffer = StubMsg.BufferStart;
2313     NdrNonConformantStringUnmarshall( &StubMsg, &mem, fmtstr_nonconf_str, 1);
2314     todo_wine
2315     ok(mem == mem_orig, "mem alloced\n");
2316     todo_wine
2317     ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called);
2318 
2319     HeapFree(GetProcessHeap(), 0, mem_orig);
2320     HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer);
2321 }
2322 
2323 static void test_conf_complex_struct(void)
2324 {
2325     RPC_MESSAGE RpcMessage;
2326     MIDL_STUB_MESSAGE StubMsg;
2327     MIDL_STUB_DESC StubDesc;
2328     void *ptr;
2329     unsigned int i;
2330     struct conf_complex
2331     {
2332       unsigned int size;
2333       unsigned int *array[1];
2334     };
2335     struct conf_complex *memsrc;
2336     struct conf_complex *mem;
2337 
2338     static const unsigned char fmtstr_complex_struct[] =
2339     {
2340 /* 0 */
2341 			0x1b,		/* FC_CARRAY */
2342 			0x3,		/* 3 */
2343 /* 2 */	NdrFcShort( 0x4 ),	/* 4 */
2344 /* 4 */	0x8,		/* Corr desc: FC_LONG */
2345 			0x0,		/*  */
2346 /* 6 */	NdrFcShort( 0xfffc ),	/* -4 */
2347 /* 8 */
2348 			0x4b,		/* FC_PP */
2349 			0x5c,		/* FC_PAD */
2350 /* 10 */
2351 			0x48,		/* FC_VARIABLE_REPEAT */
2352 			0x49,		/* FC_FIXED_OFFSET */
2353 /* 12 */	NdrFcShort( 0x4 ),	/* 4 */
2354 /* 14 */	NdrFcShort( 0x0 ),	/* 0 */
2355 /* 16 */	NdrFcShort( 0x1 ),	/* 1 */
2356 /* 18 */	NdrFcShort( 0x0 ),	/* 0 */
2357 /* 20 */	NdrFcShort( 0x0 ),	/* 0 */
2358 /* 22 */	0x12, 0x8,	/* FC_UP [simple_pointer] */
2359 /* 24 */	0x8,		/* FC_LONG */
2360 			0x5c,		/* FC_PAD */
2361 /* 26 */
2362 			0x5b,		/* FC_END */
2363 
2364 			0x8,		/* FC_LONG */
2365 /* 28 */	0x5c,		/* FC_PAD */
2366 			0x5b,		/* FC_END */
2367 /* 30 */
2368 			0x1a,		/* FC_BOGUS_STRUCT */
2369 			0x3,		/* 3 */
2370 /* 32 */	NdrFcShort( 0x4 ),	/* 4 */
2371 /* 34 */	NdrFcShort( 0xffffffde ),	/* Offset= -34 (0) */
2372 /* 36 */	NdrFcShort( 0x0 ),	/* Offset= 0 (36) */
2373 /* 38 */	0x8,		/* FC_LONG */
2374 			0x5b,		/* FC_END */
2375     };
2376 
2377     memsrc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2378                        FIELD_OFFSET(struct conf_complex, array[20]));
2379     memsrc->size = 20;
2380 
2381     StubDesc = Object_StubDesc;
2382     StubDesc.pFormatTypes = fmtstr_complex_struct;
2383 
2384     NdrClientInitializeNew(
2385                            &RpcMessage,
2386                            &StubMsg,
2387                            &StubDesc,
2388                            0);
2389 
2390     StubMsg.BufferLength = 0;
2391     NdrComplexStructBufferSize( &StubMsg,
2392                                 (unsigned char *)memsrc,
2393                                 &fmtstr_complex_struct[30] );
2394     ok(StubMsg.BufferLength >= 28, "length %d\n", StubMsg.BufferLength);
2395 
2396     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
2397     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
2398     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
2399 
2400     ptr = NdrComplexStructMarshall( &StubMsg, (unsigned char *)memsrc,
2401                                     &fmtstr_complex_struct[30] );
2402     ok(ptr == NULL, "ret %p\n", ptr);
2403     ok(*(unsigned int *)StubMsg.BufferStart == 20, "Conformance should have been 20 instead of %d\n", *(unsigned int *)StubMsg.BufferStart);
2404     ok(*(unsigned int *)(StubMsg.BufferStart + 4) == 20, "conf_complex.size should have been 20 instead of %d\n", *(unsigned int *)(StubMsg.BufferStart + 4));
2405     for (i = 0; i < 20; i++)
2406       ok(*(unsigned int *)(StubMsg.BufferStart + 8 + i * 4) == 0, "pointer id for conf_complex.array[%d] should have been 0 instead of 0x%x\n", i, *(unsigned int *)(StubMsg.BufferStart + 8 + i * 4));
2407 
2408     /* Server */
2409     my_alloc_called = 0;
2410     StubMsg.IsClient = 0;
2411     mem = NULL;
2412     StubMsg.Buffer = StubMsg.BufferStart;
2413     ptr = NdrComplexStructUnmarshall( &StubMsg, (unsigned char **)&mem, &fmtstr_complex_struct[30], 0);
2414     ok(ptr == NULL, "ret %p\n", ptr);
2415     ok(mem->size == 20, "mem->size wasn't unmarshalled correctly (%d)\n", mem->size);
2416     ok(mem->array[0] == NULL, "mem->array[0] wasn't unmarshalled correctly (%p)\n", mem->array[0]);
2417     StubMsg.pfnFree(mem);
2418 
2419     HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer);
2420     HeapFree(GetProcessHeap(), 0, memsrc);
2421 }
2422 
2423 
2424 static void test_conf_complex_array(void)
2425 {
2426     RPC_MESSAGE RpcMessage;
2427     MIDL_STUB_MESSAGE StubMsg;
2428     MIDL_STUB_DESC StubDesc;
2429     void *ptr;
2430     unsigned int i, j;
2431     struct conf_complex
2432     {
2433         unsigned int dim1, dim2;
2434         DWORD **array;
2435     };
2436     struct conf_complex memsrc;
2437     struct conf_complex *mem;
2438     DWORD *buf, expected_length;
2439 
2440     static const unsigned char fmtstr_complex_array[] =
2441     {
2442 
2443 /*  0 */        0x21,           /* FC_BOGUS_ARRAY */
2444                 0x3,            /* 3 */
2445 /*  2 */        NdrFcShort( 0x0 ),      /* 0 */
2446 /*  4 */        0x19, 0x0,      /* Corr desc:  field pointer, FC_ULONG */
2447 /*  6 */        NdrFcShort( 0x4 ),      /* 4 */
2448 /*  8 */        NdrFcLong( 0xffffffff ),        /* -1 */
2449 /* 12 */        0x8,            /* FC_LONG */
2450                 0x5b,           /* FC_END */
2451 /* 14 */
2452                 0x21,           /* FC_BOGUS_ARRAY */
2453                 0x3,            /* 3 */
2454 /* 16 */        NdrFcShort( 0x0 ),      /* 0 */
2455 /* 18 */        0x19,           /* Corr desc:  field pointer, FC_ULONG */
2456                 0x0,            /*  */
2457 /* 20 */        NdrFcShort( 0x0 ),      /* 0 */
2458 /* 22 */        NdrFcLong( 0xffffffff ),        /* -1 */
2459 /* 26 */        0x12, 0x0,      /* FC_UP */
2460 /* 28 */        NdrFcShort( 0xffe4 ),   /* Offset= -28 (0) */
2461 /* 30 */        0x5c,           /* FC_PAD */
2462                 0x5b,           /* FC_END */
2463 
2464 #ifdef _WIN64
2465 /* 32 */        0x1a,           /* FC_BOGUS_STRUCT */
2466                 0x3,            /* 3 */
2467 /* 34 */        NdrFcShort( 0x10 ),     /* 16 */
2468 /* 36 */        NdrFcShort( 0x0 ),      /* 0 */
2469 /* 38 */        NdrFcShort( 0x6 ),      /* Offset= 6 (44) */
2470 /* 40 */        0x8,            /* FC_LONG */
2471                 0x8,            /* FC_LONG */
2472 /* 42 */        0x36,           /* FC_POINTER */
2473                 0x5b,           /* FC_END */
2474 /* 44 */
2475                 0x12, 0x0,      /* FC_UP */
2476 /* 46 */        NdrFcShort( 0xffe0 ),   /* Offset= -32 (14) */
2477 #else
2478 /* 32 */
2479                 0x16,           /* FC_PSTRUCT */
2480                 0x3,            /* 3 */
2481 /* 34 */        NdrFcShort( 0xc ),      /* 12 */
2482 /* 36 */        0x4b,           /* FC_PP */
2483                 0x5c,           /* FC_PAD */
2484 /* 38 */        0x46,           /* FC_NO_REPEAT */
2485                 0x5c,           /* FC_PAD */
2486 /* 40 */        NdrFcShort( 0x8 ),      /* 8 */
2487 /* 42 */        NdrFcShort( 0x8 ),      /* 8 */
2488 /* 44 */        0x12, 0x0,      /* FC_UP */
2489 /* 46 */        NdrFcShort( 0xffe0 ),   /* Offset= -32 (14) */
2490 /* 48 */        0x5b,           /* FC_END */
2491                 0x8,            /* FC_LONG */
2492 /* 50 */        0x8,            /* FC_LONG */
2493                 0x8,            /* FC_LONG */
2494 /* 52 */        0x5c,           /* FC_PAD */
2495                 0x5b,           /* FC_END */
2496 #endif
2497     };
2498 
2499     memsrc.dim1 = 5;
2500     memsrc.dim2 = 3;
2501 
2502     memsrc.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, memsrc.dim1 * sizeof(DWORD*));
2503 
2504     for(i = 0; i < memsrc.dim1; i++)
2505     {
2506         memsrc.array[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, memsrc.dim2 * sizeof(DWORD));
2507         for(j = 0; j < memsrc.dim2; j++)
2508             memsrc.array[i][j] = i * memsrc.dim2 + j;
2509     }
2510 
2511     StubDesc = Object_StubDesc;
2512     StubDesc.pFormatTypes = fmtstr_complex_array;
2513 
2514     NdrClientInitializeNew(
2515                            &RpcMessage,
2516                            &StubMsg,
2517                            &StubDesc,
2518                            0);
2519 
2520     StubMsg.BufferLength = 0;
2521 
2522 #ifdef _WIN64
2523     NdrComplexStructBufferSize( &StubMsg,
2524                                 (unsigned char *)&memsrc,
2525                                 &fmtstr_complex_array[32] );
2526 #else
2527     NdrSimpleStructBufferSize( &StubMsg,
2528                                 (unsigned char *)&memsrc,
2529                                 &fmtstr_complex_array[32] );
2530 #endif
2531 
2532     expected_length = (4 + memsrc.dim1 * (2 + memsrc.dim2)) * 4;
2533     ok(StubMsg.BufferLength >= expected_length, "length %d\n", StubMsg.BufferLength);
2534 
2535     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
2536     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
2537     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
2538 
2539 #ifdef _WIN64
2540     ptr = NdrComplexStructMarshall( &StubMsg, (unsigned char *)&memsrc,
2541                                     &fmtstr_complex_array[32] );
2542 #else
2543     ptr = NdrSimpleStructMarshall( &StubMsg, (unsigned char *)&memsrc,
2544                                     &fmtstr_complex_array[32] );
2545 #endif
2546 
2547     ok(ptr == NULL, "ret %p\n", ptr);
2548     ok((char*)StubMsg.Buffer == (char*)StubMsg.BufferStart + expected_length, "not at expected length\n");
2549 
2550     buf = (DWORD *)StubMsg.BufferStart;
2551 
2552     ok(*buf == memsrc.dim1, "dim1 should have been %d instead of %08x\n", memsrc.dim1, *buf);
2553     buf++;
2554     ok(*buf == memsrc.dim2, "dim2 should have been %d instead of %08x\n", memsrc.dim2, *buf);
2555     buf++;
2556     ok(*buf != 0, "pointer id should be non-zero\n");
2557     buf++;
2558     ok(*buf == memsrc.dim1, "Conformance should have been %d instead of %08x\n", memsrc.dim1, *buf);
2559     buf++;
2560     for(i = 0; i < memsrc.dim1; i++)
2561     {
2562         ok(*buf != 0, "pointer id[%d] should be non-zero\n", i);
2563         buf++;
2564     }
2565     for(i = 0; i < memsrc.dim1; i++)
2566     {
2567         ok(*buf == memsrc.dim2, "Conformance should have been %d instead of %08x\n", memsrc.dim2, *buf);
2568         buf++;
2569         for(j = 0; j < memsrc.dim2; j++)
2570         {
2571             ok(*buf == i * memsrc.dim2 + j, "got %08x\n", *buf);
2572             buf++;
2573         }
2574     }
2575 
2576     ok((void*)buf == StubMsg.Buffer, "not at end of buffer\n");
2577 
2578     /* Server */
2579     my_alloc_called = 0;
2580     StubMsg.IsClient = 0;
2581     mem = NULL;
2582     StubMsg.Buffer = StubMsg.BufferStart;
2583 #ifdef _WIN64
2584     ptr = NdrComplexStructUnmarshall( &StubMsg, (unsigned char **)&mem, &fmtstr_complex_array[32], 0);
2585 #else
2586     ptr = NdrSimpleStructUnmarshall( &StubMsg, (unsigned char **)&mem, &fmtstr_complex_array[32], 0);
2587 #endif
2588     ok(ptr == NULL, "ret %p\n", ptr);
2589     ok(mem->dim1 == memsrc.dim1, "mem->dim1 wasn't unmarshalled correctly (%d)\n", mem->dim1);
2590     ok(mem->dim2 == memsrc.dim2, "mem->dim2 wasn't unmarshalled correctly (%d)\n", mem->dim2);
2591     ok(mem->array[1][0] == memsrc.dim2, "mem->array[1][0] wasn't unmarshalled correctly (%d)\n", mem->array[1][0]);
2592 
2593     StubMsg.Buffer = StubMsg.BufferStart;
2594 #ifdef _WIN64
2595     NdrComplexStructFree( &StubMsg, (unsigned char*)mem, &fmtstr_complex_array[32]);
2596 #else
2597     NdrSimpleStructFree( &StubMsg, (unsigned char*)mem, &fmtstr_complex_array[32]);
2598 #endif
2599 
2600     HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer);
2601 
2602     for(i = 0; i < memsrc.dim1; i++)
2603         HeapFree(GetProcessHeap(), 0, memsrc.array[i]);
2604     HeapFree(GetProcessHeap(), 0, memsrc.array);
2605 }
2606 
2607 static void test_ndr_buffer(void)
2608 {
2609     static unsigned char ncalrpc[] = "ncalrpc";
2610     static unsigned char endpoint[] = "winetest:test_ndr_buffer";
2611     RPC_MESSAGE RpcMessage;
2612     MIDL_STUB_MESSAGE StubMsg;
2613     MIDL_STUB_DESC StubDesc = Object_StubDesc;
2614     unsigned char *ret;
2615     unsigned char *binding;
2616     RPC_BINDING_HANDLE Handle;
2617     RPC_STATUS status;
2618     ULONG prev_buffer_length;
2619     BOOL old_buffer_valid_location;
2620 
2621     StubDesc.RpcInterfaceInformation = (void *)&IFoo___RpcServerInterface;
2622 
2623     status = RpcServerUseProtseqEpA(ncalrpc, 20, endpoint, NULL);
2624     ok(RPC_S_OK == status, "RpcServerUseProtseqEp failed with status %u\n", status);
2625     status = RpcServerRegisterIf(IFoo_v0_0_s_ifspec, NULL, NULL);
2626     ok(RPC_S_OK == status, "RpcServerRegisterIf failed with status %u\n", status);
2627     status = RpcServerListen(1, 20, TRUE);
2628     ok(RPC_S_OK == status, "RpcServerListen failed with status %u\n", status);
2629     if (status != RPC_S_OK)
2630     {
2631         /* Failed to create a server, running client tests is useless */
2632         return;
2633     }
2634 
2635     status = RpcStringBindingComposeA(NULL, ncalrpc, NULL, endpoint, NULL, &binding);
2636     ok(status == RPC_S_OK, "RpcStringBindingCompose failed (%u)\n", status);
2637 
2638     status = RpcBindingFromStringBindingA(binding, &Handle);
2639     ok(status == RPC_S_OK, "RpcBindingFromStringBinding failed (%u)\n", status);
2640     RpcStringFreeA(&binding);
2641 
2642     NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 5);
2643 
2644     ret = NdrGetBuffer(&StubMsg, 10, Handle);
2645     ok(ret == StubMsg.Buffer, "NdrGetBuffer should have returned the same value as StubMsg.Buffer instead of %p\n", ret);
2646     ok(RpcMessage.Handle != NULL, "RpcMessage.Handle should not have been NULL\n");
2647     ok(RpcMessage.Buffer != NULL, "RpcMessage.Buffer should not have been NULL\n");
2648     ok(RpcMessage.BufferLength == 10 ||
2649        broken(RpcMessage.BufferLength == 12), /* win2k */
2650        "RpcMessage.BufferLength should have been 10 instead of %d\n", RpcMessage.BufferLength);
2651     ok(RpcMessage.RpcFlags == 0, "RpcMessage.RpcFlags should have been 0x0 instead of 0x%x\n", RpcMessage.RpcFlags);
2652     ok(StubMsg.Buffer != NULL, "Buffer should not have been NULL\n");
2653     ok(!StubMsg.BufferStart, "BufferStart should have been NULL instead of %p\n", StubMsg.BufferStart);
2654     ok(!StubMsg.BufferEnd, "BufferEnd should have been NULL instead of %p\n", StubMsg.BufferEnd);
2655 todo_wine
2656     ok(StubMsg.BufferLength == 0, "BufferLength should have left as 0 instead of being set to %d\n", StubMsg.BufferLength);
2657     old_buffer_valid_location = !StubMsg.fBufferValid;
2658     if (old_buffer_valid_location)
2659         ok(broken(StubMsg.CorrDespIncrement == TRUE), "fBufferValid should have been TRUE instead of 0x%x\n", StubMsg.CorrDespIncrement);
2660     else
2661         ok(StubMsg.fBufferValid, "fBufferValid should have been non-zero instead of 0x%x\n", StubMsg.fBufferValid);
2662 
2663     prev_buffer_length = RpcMessage.BufferLength;
2664     StubMsg.BufferLength = 1;
2665     NdrFreeBuffer(&StubMsg);
2666     ok(RpcMessage.Handle != NULL, "RpcMessage.Handle should not have been NULL\n");
2667     ok(RpcMessage.Buffer != NULL, "RpcMessage.Buffer should not have been NULL\n");
2668     ok(RpcMessage.BufferLength == prev_buffer_length, "RpcMessage.BufferLength should have been left as %d instead of %d\n", prev_buffer_length, RpcMessage.BufferLength);
2669     ok(StubMsg.Buffer != NULL, "Buffer should not have been NULL\n");
2670     ok(StubMsg.BufferLength == 1, "BufferLength should have left as 1 instead of being set to %d\n", StubMsg.BufferLength);
2671     if (old_buffer_valid_location)
2672         ok(broken(StubMsg.CorrDespIncrement == FALSE), "fBufferValid should have been FALSE instead of 0x%x\n", StubMsg.CorrDespIncrement);
2673     else
2674         ok(!StubMsg.fBufferValid, "fBufferValid should have been FALSE instead of %d\n", StubMsg.fBufferValid);
2675 
2676     /* attempt double-free */
2677     NdrFreeBuffer(&StubMsg);
2678 
2679     RpcBindingFree(&Handle);
2680 
2681     status = RpcServerUnregisterIf(NULL, NULL, FALSE);
2682     ok(status == RPC_S_OK, "RpcServerUnregisterIf failed (%u)\n", status);
2683 }
2684 
2685 static void test_NdrMapCommAndFaultStatus(void)
2686 {
2687     RPC_STATUS rpc_status;
2688     MIDL_STUB_MESSAGE StubMsg;
2689     RPC_MESSAGE RpcMessage;
2690 
2691     NdrClientInitializeNew(&RpcMessage, &StubMsg, &Object_StubDesc, 5);
2692 
2693     for (rpc_status = 0; rpc_status < 10000; rpc_status++)
2694     {
2695         RPC_STATUS status;
2696         ULONG comm_status = 0;
2697         ULONG fault_status = 0;
2698         ULONG expected_comm_status = 0;
2699         ULONG expected_fault_status = 0;
2700         status = NdrMapCommAndFaultStatus(&StubMsg, &comm_status, &fault_status, rpc_status);
2701         ok(status == RPC_S_OK, "NdrMapCommAndFaultStatus failed with error %d\n", status);
2702         switch (rpc_status)
2703         {
2704         case ERROR_INVALID_HANDLE:
2705         case RPC_S_INVALID_BINDING:
2706         case RPC_S_UNKNOWN_IF:
2707         case RPC_S_SERVER_UNAVAILABLE:
2708         case RPC_S_SERVER_TOO_BUSY:
2709         case RPC_S_CALL_FAILED_DNE:
2710         case RPC_S_PROTOCOL_ERROR:
2711         case RPC_S_UNSUPPORTED_TRANS_SYN:
2712         case RPC_S_UNSUPPORTED_TYPE:
2713         case RPC_S_PROCNUM_OUT_OF_RANGE:
2714         case EPT_S_NOT_REGISTERED:
2715         case RPC_S_COMM_FAILURE:
2716             expected_comm_status = rpc_status;
2717             break;
2718         default:
2719             expected_fault_status = rpc_status;
2720         }
2721         ok(comm_status == expected_comm_status, "NdrMapCommAndFaultStatus should have mapped %d to comm status %d instead of %d\n",
2722             rpc_status, expected_comm_status, comm_status);
2723         ok(fault_status == expected_fault_status, "NdrMapCommAndFaultStatus should have mapped %d to fault status %d instead of %d\n",
2724             rpc_status, expected_fault_status, fault_status);
2725     }
2726 }
2727 
2728 static void test_NdrGetUserMarshalInfo(void)
2729 {
2730     RPC_STATUS status;
2731     MIDL_STUB_MESSAGE stubmsg;
2732     USER_MARSHAL_CB umcb;
2733     NDR_USER_MARSHAL_INFO umi;
2734     unsigned char buffer[16];
2735     void *rpc_channel_buffer = (void *)(ULONG_PTR)0xcafebabe;
2736     RPC_MESSAGE rpc_msg;
2737 
2738     /* unmarshall */
2739 
2740     memset(&rpc_msg, 0xcc, sizeof(rpc_msg));
2741     rpc_msg.Buffer = buffer;
2742     rpc_msg.BufferLength = 16;
2743 
2744     memset(&stubmsg, 0xcc, sizeof(stubmsg));
2745     stubmsg.RpcMsg = &rpc_msg;
2746     stubmsg.dwDestContext = MSHCTX_INPROC;
2747     stubmsg.pvDestContext = NULL;
2748     stubmsg.Buffer = buffer + 15;
2749     stubmsg.BufferLength = 0;
2750     stubmsg.BufferEnd = NULL;
2751     stubmsg.pRpcChannelBuffer = rpc_channel_buffer;
2752     stubmsg.StubDesc = NULL;
2753     stubmsg.pfnAllocate = my_alloc;
2754     stubmsg.pfnFree = my_free;
2755 
2756     memset(&umcb, 0xcc, sizeof(umcb));
2757     umcb.Flags = MAKELONG(MSHCTX_INPROC, NDR_LOCAL_DATA_REPRESENTATION);
2758     umcb.pStubMsg = &stubmsg;
2759     umcb.Signature = USER_MARSHAL_CB_SIGNATURE;
2760     umcb.CBType = USER_MARSHAL_CB_UNMARSHALL;
2761 
2762     memset(&umi, 0xaa, sizeof(umi));
2763 
2764     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2765     ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status);
2766     ok( umi.InformationLevel == 1,
2767        "umi.InformationLevel was %u instead of 1\n",
2768         umi.InformationLevel);
2769     ok( U1(umi).Level1.Buffer == buffer + 15,
2770        "umi.Level1.Buffer was %p instead of %p\n",
2771         U1(umi).Level1.Buffer, buffer);
2772     ok( U1(umi).Level1.BufferSize == 1,
2773        "umi.Level1.BufferSize was %u instead of 1\n",
2774         U1(umi).Level1.BufferSize);
2775     ok( U1(umi).Level1.pfnAllocate == my_alloc,
2776        "umi.Level1.pfnAllocate was %p instead of %p\n",
2777         U1(umi).Level1.pfnAllocate, my_alloc);
2778     ok( U1(umi).Level1.pfnFree == my_free,
2779        "umi.Level1.pfnFree was %p instead of %p\n",
2780         U1(umi).Level1.pfnFree, my_free);
2781     ok( U1(umi).Level1.pRpcChannelBuffer == rpc_channel_buffer,
2782        "umi.Level1.pRpcChannelBuffer was %p instead of %p\n",
2783         U1(umi).Level1.pRpcChannelBuffer, rpc_channel_buffer);
2784 
2785     /* buffer size */
2786 
2787     rpc_msg.Buffer = buffer;
2788     rpc_msg.BufferLength = 16;
2789 
2790     stubmsg.Buffer = buffer;
2791     stubmsg.BufferLength = 16;
2792     stubmsg.BufferEnd = NULL;
2793 
2794     umcb.CBType = USER_MARSHAL_CB_BUFFER_SIZE;
2795 
2796     memset(&umi, 0xaa, sizeof(umi));
2797 
2798     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2799     ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status);
2800     ok( umi.InformationLevel == 1,
2801        "umi.InformationLevel was %u instead of 1\n",
2802         umi.InformationLevel);
2803     ok( U1(umi).Level1.Buffer == NULL,
2804        "umi.Level1.Buffer was %p instead of NULL\n",
2805         U1(umi).Level1.Buffer);
2806     ok( U1(umi).Level1.BufferSize == 0,
2807        "umi.Level1.BufferSize was %u instead of 0\n",
2808         U1(umi).Level1.BufferSize);
2809     ok( U1(umi).Level1.pfnAllocate == my_alloc,
2810        "umi.Level1.pfnAllocate was %p instead of %p\n",
2811         U1(umi).Level1.pfnAllocate, my_alloc);
2812     ok( U1(umi).Level1.pfnFree == my_free,
2813        "umi.Level1.pfnFree was %p instead of %p\n",
2814         U1(umi).Level1.pfnFree, my_free);
2815     ok( U1(umi).Level1.pRpcChannelBuffer == rpc_channel_buffer,
2816        "umi.Level1.pRpcChannelBuffer was %p instead of %p\n",
2817         U1(umi).Level1.pRpcChannelBuffer, rpc_channel_buffer);
2818 
2819     /* marshall */
2820 
2821     rpc_msg.Buffer = buffer;
2822     rpc_msg.BufferLength = 16;
2823 
2824     stubmsg.Buffer = buffer + 15;
2825     stubmsg.BufferLength = 0;
2826     stubmsg.BufferEnd = NULL;
2827 
2828     umcb.CBType = USER_MARSHAL_CB_MARSHALL;
2829 
2830     memset(&umi, 0xaa, sizeof(umi));
2831 
2832     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2833     ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status);
2834     ok( umi.InformationLevel == 1,
2835        "umi.InformationLevel was %u instead of 1\n",
2836         umi.InformationLevel);
2837     ok( U1(umi).Level1.Buffer == buffer + 15,
2838        "umi.Level1.Buffer was %p instead of %p\n",
2839         U1(umi).Level1.Buffer, buffer);
2840     ok( U1(umi).Level1.BufferSize == 1,
2841        "umi.Level1.BufferSize was %u instead of 1\n",
2842         U1(umi).Level1.BufferSize);
2843     ok( U1(umi).Level1.pfnAllocate == my_alloc,
2844        "umi.Level1.pfnAllocate was %p instead of %p\n",
2845         U1(umi).Level1.pfnAllocate, my_alloc);
2846     ok( U1(umi).Level1.pfnFree == my_free,
2847        "umi.Level1.pfnFree was %p instead of %p\n",
2848         U1(umi).Level1.pfnFree, my_free);
2849     ok( U1(umi).Level1.pRpcChannelBuffer == rpc_channel_buffer,
2850        "umi.Level1.pRpcChannelBuffer was %p instead of %p\n",
2851         U1(umi).Level1.pRpcChannelBuffer, rpc_channel_buffer);
2852 
2853     /* free */
2854 
2855     rpc_msg.Buffer = buffer;
2856     rpc_msg.BufferLength = 16;
2857 
2858     stubmsg.Buffer = buffer;
2859     stubmsg.BufferLength = 16;
2860     stubmsg.BufferEnd = NULL;
2861 
2862     umcb.CBType = USER_MARSHAL_CB_FREE;
2863 
2864     memset(&umi, 0xaa, sizeof(umi));
2865 
2866     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2867     ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status);
2868     ok( umi.InformationLevel == 1,
2869        "umi.InformationLevel was %u instead of 1\n",
2870         umi.InformationLevel);
2871     ok( U1(umi).Level1.Buffer == NULL,
2872        "umi.Level1.Buffer was %p instead of NULL\n",
2873         U1(umi).Level1.Buffer);
2874     ok( U1(umi).Level1.BufferSize == 0,
2875        "umi.Level1.BufferSize was %u instead of 0\n",
2876         U1(umi).Level1.BufferSize);
2877     ok( U1(umi).Level1.pfnAllocate == my_alloc,
2878        "umi.Level1.pfnAllocate was %p instead of %p\n",
2879         U1(umi).Level1.pfnAllocate, my_alloc);
2880     ok( U1(umi).Level1.pfnFree == my_free,
2881        "umi.Level1.pfnFree was %p instead of %p\n",
2882         U1(umi).Level1.pfnFree, my_free);
2883     ok( U1(umi).Level1.pRpcChannelBuffer == rpc_channel_buffer,
2884        "umi.Level1.pRpcChannelBuffer was %p instead of %p\n",
2885         U1(umi).Level1.pRpcChannelBuffer, rpc_channel_buffer);
2886 
2887     /* boundary test */
2888 
2889     rpc_msg.Buffer = buffer;
2890     rpc_msg.BufferLength = 15;
2891 
2892     stubmsg.Buffer = buffer + 15;
2893     stubmsg.BufferLength = 0;
2894     stubmsg.BufferEnd = NULL;
2895 
2896     umcb.CBType = USER_MARSHAL_CB_MARSHALL;
2897 
2898     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2899     ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status);
2900     ok( U1(umi).Level1.BufferSize == 0,
2901        "umi.Level1.BufferSize was %u instead of 0\n",
2902         U1(umi).Level1.BufferSize);
2903 
2904     /* error conditions */
2905 
2906     rpc_msg.BufferLength = 14;
2907     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2908     ok(status == ERROR_INVALID_USER_BUFFER,
2909         "NdrGetUserMarshalInfo should have failed with ERROR_INVALID_USER_BUFFER instead of %d\n", status);
2910 
2911     rpc_msg.BufferLength = 15;
2912     status = NdrGetUserMarshalInfo(&umcb.Flags, 9999, &umi);
2913     ok(status == RPC_S_INVALID_ARG,
2914         "NdrGetUserMarshalInfo should have failed with RPC_S_INVALID_ARG instead of %d\n", status);
2915 
2916     umcb.CBType = 9999;
2917     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2918     ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status);
2919 
2920     umcb.CBType = USER_MARSHAL_CB_MARSHALL;
2921     umcb.Signature = 0;
2922     status = NdrGetUserMarshalInfo(&umcb.Flags, 1, &umi);
2923     ok(status == RPC_S_INVALID_ARG,
2924         "NdrGetUserMarshalInfo should have failed with RPC_S_INVALID_ARG instead of %d\n", status);
2925 }
2926 
2927 static void test_MesEncodeFixedBufferHandleCreate(void)
2928 {
2929     ULONG encoded_size;
2930     RPC_STATUS status;
2931     handle_t handle;
2932     char *buffer;
2933 
2934     status = MesEncodeFixedBufferHandleCreate(NULL, 0, NULL, NULL);
2935     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2936 
2937     status = MesEncodeFixedBufferHandleCreate(NULL, 0, NULL, &handle);
2938     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2939 
2940     status = MesEncodeFixedBufferHandleCreate((char*)0xdeadbeef, 0, NULL, &handle);
2941     ok(status == RPC_X_INVALID_BUFFER, "got %d\n", status);
2942 
2943     buffer = (void*)((0xdeadbeef + 7) & ~7);
2944     status = MesEncodeFixedBufferHandleCreate(buffer, 0, NULL, &handle);
2945     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2946 
2947     status = MesEncodeFixedBufferHandleCreate(buffer, 0, &encoded_size, &handle);
2948 todo_wine
2949     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2950 if (status == RPC_S_OK) {
2951     MesHandleFree(handle);
2952 }
2953     status = MesEncodeFixedBufferHandleCreate(buffer, 32, NULL, &handle);
2954     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2955 
2956     status = MesEncodeFixedBufferHandleCreate(buffer, 32, &encoded_size, &handle);
2957     ok(status == RPC_S_OK, "got %d\n", status);
2958 
2959     status = MesBufferHandleReset(NULL, MES_DYNAMIC_BUFFER_HANDLE, MES_ENCODE,
2960         &buffer, 32, &encoded_size);
2961     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2962 
2963     /* convert to dynamic buffer handle */
2964     status = MesBufferHandleReset(handle, MES_DYNAMIC_BUFFER_HANDLE, MES_ENCODE,
2965         &buffer, 32, &encoded_size);
2966     ok(status == RPC_S_OK, "got %d\n", status);
2967 
2968     status = MesBufferHandleReset(handle, MES_DYNAMIC_BUFFER_HANDLE, MES_ENCODE,
2969         NULL, 32, &encoded_size);
2970     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2971 
2972     status = MesBufferHandleReset(handle, MES_DYNAMIC_BUFFER_HANDLE, MES_ENCODE,
2973         &buffer, 32, NULL);
2974     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2975 
2976     /* invalid handle type */
2977     status = MesBufferHandleReset(handle, MES_DYNAMIC_BUFFER_HANDLE+1, MES_ENCODE,
2978         &buffer, 32, &encoded_size);
2979     ok(status == RPC_S_INVALID_ARG, "got %d\n", status);
2980 
2981     status = MesHandleFree(handle);
2982     ok(status == RPC_S_OK, "got %d\n", status);
2983 }
2984 
2985 static void test_NdrCorrelationInitialize(void)
2986 {
2987     MIDL_STUB_MESSAGE stub_msg;
2988     BYTE buf[256];
2989 
2990     memset( &stub_msg, 0, sizeof(stub_msg) );
2991     memset( buf, 0, sizeof(buf) );
2992 
2993     NdrCorrelationInitialize( &stub_msg, buf, sizeof(buf), 0 );
2994     ok( stub_msg.CorrDespIncrement == 2 ||
2995         broken(stub_msg.CorrDespIncrement == 0), /* <= Win 2003 */
2996         "got %d\n", stub_msg.CorrDespIncrement );
2997 
2998     memset( &stub_msg, 0, sizeof(stub_msg) );
2999     memset( buf, 0, sizeof(buf) );
3000 
3001     stub_msg.CorrDespIncrement = 1;
3002     NdrCorrelationInitialize( &stub_msg, buf, sizeof(buf), 0 );
3003     ok( stub_msg.CorrDespIncrement == 1, "got %d\n", stub_msg.CorrDespIncrement );
3004 }
3005 
3006 START_TEST( ndr_marshall )
3007 {
3008     determine_pointer_marshalling_style();
3009 
3010     test_ndr_simple_type();
3011     test_simple_types();
3012     test_nontrivial_pointer_types();
3013     test_simple_struct();
3014     test_struct_align();
3015     test_iface_ptr();
3016     test_fullpointer_xlat();
3017     test_client_init();
3018     test_server_init();
3019     test_ndr_allocate();
3020     test_conformant_array();
3021     test_conformant_string();
3022     test_nonconformant_string();
3023     test_conf_complex_struct();
3024     test_conf_complex_array();
3025     test_ndr_buffer();
3026     test_NdrMapCommAndFaultStatus();
3027     test_NdrGetUserMarshalInfo();
3028     test_MesEncodeFixedBufferHandleCreate();
3029     test_NdrCorrelationInitialize();
3030 }
3031