rpcrt4: Store the QueryType in the state table in NdrFullPointerQueryRefId.
[wine] / dlls / rpcrt4 / tests / ndr_marshall.c
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 #include <stdarg.h>
22
23 #include "wine/test.h"
24 #include <windef.h>
25 #include <winbase.h>
26 #include <winnt.h>
27 #include <winerror.h>
28
29 #include "rpc.h"
30 #include "rpcdce.h"
31 #include "rpcproxy.h"
32
33
34 static int my_alloc_called;
35 static int my_free_called;
36 void * CALLBACK my_alloc(size_t size)
37 {
38     my_alloc_called++;
39     return NdrOleAllocate(size);
40 }
41
42 void CALLBACK my_free(void *ptr)
43 {
44     my_free_called++;
45     return NdrOleFree(ptr);
46 }
47
48 static const MIDL_STUB_DESC Object_StubDesc = 
49     {
50     NULL,
51     my_alloc,
52     my_free,
53     { 0 },
54     0,
55     0,
56     0,
57     0,
58     NULL, /* format string, filled in by tests */
59     1, /* -error bounds_check flag */
60     0x20000, /* Ndr library version */
61     0,
62     0x50100a4, /* MIDL Version 5.1.164 */
63     0,
64     NULL,
65     0,  /* notify & notify_flag routine table */
66     1,  /* Flags */
67     0,  /* Reserved3 */
68     0,  /* Reserved4 */
69     0   /* Reserved5 */
70     };
71
72
73 static void test_pointer_marshal(const unsigned char *formattypes,
74                                  void *memsrc,
75                                  long srcsize,
76                                  const void *wiredata,
77                                  long wiredatalen,
78                                  int(*cmp)(const void*,const void*,size_t),
79                                  long num_additional_allocs,
80                                  const char *msgpfx)
81 {
82     RPC_MESSAGE RpcMessage;
83     MIDL_STUB_MESSAGE StubMsg;
84     MIDL_STUB_DESC StubDesc;
85     DWORD size;
86     void *ptr;
87     unsigned char *mem, *mem_orig;
88
89     my_alloc_called = my_free_called = 0;
90     if(!cmp)
91         cmp = memcmp;
92
93     StubDesc = Object_StubDesc;
94     StubDesc.pFormatTypes = formattypes;
95
96     NdrClientInitializeNew(
97                            &RpcMessage,
98                            &StubMsg,
99                            &StubDesc,
100                            0);
101
102     StubMsg.BufferLength = 0;
103     NdrPointerBufferSize( &StubMsg,
104                           memsrc,
105                           formattypes );
106     ok(StubMsg.BufferLength >= wiredatalen, "%s: length %ld\n", msgpfx, StubMsg.BufferLength);
107
108     /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/
109     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
110     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
111
112     memset(StubMsg.BufferStart, 0x0, StubMsg.BufferLength); /* This is a hack to clear the padding between the ptr and longlong/double */
113
114     ptr = NdrPointerMarshall( &StubMsg,  memsrc, formattypes );
115     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
116     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
117     ok(!memcmp(StubMsg.BufferStart, wiredata, wiredatalen), "%s: incorrectly marshaled\n", msgpfx);
118
119     StubMsg.Buffer = StubMsg.BufferStart;
120     StubMsg.MemorySize = 0;
121
122 #if 0 /* NdrPointerMemorySize crashes under Wine, remove #if 0 when this is fixed */
123     size = NdrPointerMemorySize( &StubMsg, formattypes );
124     ok(size == StubMsg.MemorySize, "%s: mem size %ld size %ld\n", msgpfx, StubMsg.MemorySize, size); 
125     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); 
126     if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */)
127         ok(size == srcsize + 4, "%s: mem size %ld\n", msgpfx, size);
128     else
129         ok(size == srcsize, "%s: mem size %ld\n", msgpfx, size);
130
131     StubMsg.Buffer = StubMsg.BufferStart;
132     StubMsg.MemorySize = 16;
133     size = NdrPointerMemorySize( &StubMsg, formattypes );
134     ok(size == StubMsg.MemorySize, "%s: mem size %ld size %ld\n", msgpfx, StubMsg.MemorySize, size); 
135     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); 
136     if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */)
137         ok(size == srcsize + 4 + 16, "%s: mem size %ld\n", msgpfx, size);
138     else
139         ok(size == srcsize + 16, "%s: mem size %ld\n", msgpfx, size);
140  
141     StubMsg.Buffer = StubMsg.BufferStart;
142     StubMsg.MemorySize = 1;
143     size = NdrPointerMemorySize( &StubMsg, formattypes );
144     ok(size == StubMsg.MemorySize, "%s: mem size %ld size %ld\n", msgpfx, StubMsg.MemorySize, size); 
145     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); 
146     if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */)
147         ok(size == srcsize + 4 + (srcsize == 8 ? 8 : 4), "%s: mem size %ld\n", msgpfx, size);
148     else
149         ok(size == srcsize + (srcsize == 8 ? 8 : 4), "%s: mem size %ld\n", msgpfx, size);
150
151 #endif
152
153     size = srcsize;
154     if(formattypes[1] & 0x10) size += 4;
155
156     StubMsg.Buffer = StubMsg.BufferStart;
157     StubMsg.MemorySize = 0;
158     mem_orig = mem = HeapAlloc(GetProcessHeap(), 0, size); 
159
160     if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */)
161         *(void**)mem = NULL;
162     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
163     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
164     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
165     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
166     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
167     ok(StubMsg.MemorySize == 0, "%s: memorysize %ld\n", msgpfx, StubMsg.MemorySize);
168     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called); 
169     my_alloc_called = 0;
170
171     /* reset the buffer and call with must alloc */
172     StubMsg.Buffer = StubMsg.BufferStart;
173     if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */)
174         *(void**)mem = NULL;
175     ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 1 );
176     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
177     /* doesn't allocate mem in this case */
178 todo_wine {
179     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
180  }
181     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
182     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
183     ok(StubMsg.MemorySize == 0, "%s: memorysize %ld\n", msgpfx, StubMsg.MemorySize);
184
185 todo_wine {
186     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called); 
187 }
188     my_alloc_called = 0;
189     if(formattypes[0] != 0x11 /* FC_RP */)
190     {
191         /* now pass the address of a NULL ptr */
192         mem = NULL;
193         StubMsg.Buffer = StubMsg.BufferStart;
194         ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
195         ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
196         ok(mem != StubMsg.BufferStart + wiredatalen - srcsize, "%s: mem points to buffer %p %p\n", msgpfx, mem, StubMsg.BufferStart);
197         ok(!cmp(mem, memsrc, size), "%s: incorrectly unmarshaled\n", msgpfx);
198         ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
199         ok(StubMsg.MemorySize == 0, "%s: memorysize %ld\n", msgpfx, StubMsg.MemorySize);
200         ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called); 
201         my_alloc_called = 0;
202         NdrPointerFree(&StubMsg, mem, formattypes);
203  
204         /* again pass address of NULL ptr, but pretend we're a server */
205         mem = NULL;
206         StubMsg.Buffer = StubMsg.BufferStart;
207         StubMsg.IsClient = 0;
208         ptr = NdrPointerUnmarshall( &StubMsg, &mem, formattypes, 0 );
209         ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
210 todo_wine {
211         ok(mem == StubMsg.BufferStart + wiredatalen - srcsize, "%s: mem doesn't point to buffer %p %p\n", msgpfx, mem, StubMsg.BufferStart);
212  }
213         ok(!cmp(mem, memsrc, size), "%s: incorrecly unmarshaled\n", msgpfx);
214         ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %ld\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen);
215         ok(StubMsg.MemorySize == 0, "%s: memorysize %ld\n", msgpfx, StubMsg.MemorySize); 
216 todo_wine {
217         ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called); 
218         my_alloc_called = 0;
219  }
220     }
221     HeapFree(GetProcessHeap(), 0, mem_orig);
222     HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart);
223 }
224
225 static int deref_cmp(const void *s1, const void *s2, size_t num)
226 {
227     return memcmp(*(void**)s1, *(void**)s2, num);
228 }
229
230
231 static void test_simple_types()
232 {
233     unsigned char wiredata[16];
234     unsigned char ch;
235     unsigned char *ch_ptr;
236     unsigned short s;
237     unsigned int i;
238     unsigned long l;
239     ULONGLONG ll;
240     float f;
241     double d;
242
243     static const unsigned char fmtstr_up_char[] =
244     {
245         0x12, 0x8,      /* FC_UP [simple_pointer] */
246         0x2,            /* FC_CHAR */
247         0x5c,           /* FC_PAD */
248     };
249     static const unsigned char fmtstr_up_byte[] =
250     {
251         0x12, 0x8,      /* FC_UP [simple_pointer] */
252         0x1,            /* FC_BYTE */
253         0x5c,           /* FC_PAD */
254     };
255     static const unsigned char fmtstr_up_small[] =
256     {
257         0x12, 0x8,      /* FC_UP [simple_pointer] */
258         0x3,            /* FC_SMALL */
259         0x5c,           /* FC_PAD */
260     };
261     static const unsigned char fmtstr_up_usmall[] =
262     {
263         0x12, 0x8,      /* FC_UP [simple_pointer] */
264         0x4,            /* FC_USMALL */
265         0x5c,           /* FC_PAD */
266     };  
267     static const unsigned char fmtstr_rp_char[] =
268     {
269         0x11, 0x8,      /* FC_RP [simple_pointer] */
270         0x2,            /* FC_CHAR */
271         0x5c,           /* FC_PAD */
272     };
273     static const unsigned char fmtstr_rpup_char[] =
274     {
275         0x11, 0x14,     /* FC_RP [alloced_on_stack] */
276         NdrFcShort( 0x2 ),      /* Offset= 2 (4) */
277         0x12, 0x8,      /* FC_UP [simple_pointer] */
278         0x2,            /* FC_CHAR */
279         0x5c,           /* FC_PAD */
280     };
281     static const unsigned char fmtstr_rpup_char2[] =
282     {
283         0x11, 0x04,     /* FC_RP [alloced_on_stack] */
284         NdrFcShort( 0x2 ),      /* Offset= 2 (4) */
285         0x12, 0x8,      /* FC_UP [simple_pointer] */
286         0x2,            /* FC_CHAR */
287         0x5c,           /* FC_PAD */
288     };
289
290     static const unsigned char fmtstr_up_wchar[] =
291     {
292         0x12, 0x8,      /* FC_UP [simple_pointer] */
293         0x5,            /* FC_WCHAR */
294         0x5c,           /* FC_PAD */
295     };
296     static const unsigned char fmtstr_up_short[] =
297     {
298         0x12, 0x8,      /* FC_UP [simple_pointer] */
299         0x6,            /* FC_SHORT */
300         0x5c,           /* FC_PAD */
301     };
302     static const unsigned char fmtstr_up_ushort[] =
303     {
304         0x12, 0x8,      /* FC_UP [simple_pointer] */
305         0x7,            /* FC_USHORT */
306         0x5c,           /* FC_PAD */
307     };
308 #if 0
309     static const unsigned char fmtstr_up_enum16[] =
310     {
311         0x12, 0x8,      /* FC_UP [simple_pointer] */
312         0xd,            /* FC_ENUM16 */
313         0x5c,           /* FC_PAD */
314     };
315 #endif
316     static const unsigned char fmtstr_up_long[] =
317     {
318         0x12, 0x8,      /* FC_UP [simple_pointer] */
319         0x8,            /* FC_LONG */
320         0x5c,           /* FC_PAD */
321     };
322     static const unsigned char fmtstr_up_ulong[] =
323     {
324         0x12, 0x8,      /* FC_UP [simple_pointer] */
325         0x9,            /* FC_ULONG */
326         0x5c,           /* FC_PAD */
327     };
328     static const unsigned char fmtstr_up_enum32[] =
329     {
330         0x12, 0x8,      /* FC_UP [simple_pointer] */
331         0xe,            /* FC_ENUM32 */
332         0x5c,           /* FC_PAD */
333     };
334     static const unsigned char fmtstr_up_errorstatus[] =
335     {
336         0x12, 0x8,      /* FC_UP [simple_pointer] */
337         0x10,           /* FC_ERROR_STATUS_T */
338         0x5c,           /* FC_PAD */
339     };
340
341     static const unsigned char fmtstr_up_longlong[] =
342     {
343         0x12, 0x8,      /* FC_UP [simple_pointer] */
344         0xb,            /* FC_HYPER */
345         0x5c,           /* FC_PAD */
346     };
347     static const unsigned char fmtstr_up_float[] =
348     {
349         0x12, 0x8,      /* FC_UP [simple_pointer] */
350         0xa,            /* FC_FLOAT */
351         0x5c,           /* FC_PAD */
352     };
353     static const unsigned char fmtstr_up_double[] =
354     {
355         0x12, 0x8,      /* FC_UP [simple_pointer] */
356         0xc,            /* FC_DOUBLE */
357         0x5c,           /* FC_PAD */
358     };
359
360     ch = 0xa5;
361     ch_ptr = &ch;
362     *(void**)wiredata = ch_ptr;
363     wiredata[sizeof(void*)] = ch;
364  
365     test_pointer_marshal(fmtstr_up_char, ch_ptr, 1, wiredata, 5, NULL, 0, "up_char");
366     test_pointer_marshal(fmtstr_up_byte, ch_ptr, 1, wiredata, 5, NULL, 0, "up_byte");
367     test_pointer_marshal(fmtstr_up_small, ch_ptr, 1, wiredata, 5, NULL, 0,  "up_small");
368     test_pointer_marshal(fmtstr_up_usmall, ch_ptr, 1, wiredata, 5, NULL, 0, "up_usmall");
369
370     test_pointer_marshal(fmtstr_rp_char, ch_ptr, 1, &ch, 1, NULL, 0, "rp_char");
371
372     test_pointer_marshal(fmtstr_rpup_char, &ch_ptr, 1, wiredata, 5, deref_cmp, 1, "rpup_char");
373     test_pointer_marshal(fmtstr_rpup_char2, ch_ptr, 1, wiredata, 5, NULL, 0, "rpup_char2");
374
375     s = 0xa597;
376     *(void**)wiredata = &s;
377     *(unsigned short*)(wiredata + sizeof(void*)) = s;
378
379     test_pointer_marshal(fmtstr_up_wchar, &s, 2, wiredata, 6, NULL, 0, "up_wchar");
380     test_pointer_marshal(fmtstr_up_short, &s, 2, wiredata, 6, NULL, 0, "up_short");
381     test_pointer_marshal(fmtstr_up_ushort, &s, 2, wiredata, 6, NULL, 0, "up_ushort");
382
383     i = s;
384     *(void**)wiredata = &i;
385 #if 0 /* Not sure why this crashes under Windows */
386     test_pointer_marshal(fmtstr_up_enum16, &i, 2, wiredata, 6, NULL, 0, "up_enum16");
387 #endif
388
389     l = 0xcafebabe;
390     *(void**)wiredata = &l;
391     *(unsigned long*)(wiredata + sizeof(void*)) = l;
392
393     test_pointer_marshal(fmtstr_up_long, &l, 4, wiredata, 8, NULL, 0, "up_long");
394     test_pointer_marshal(fmtstr_up_ulong, &l, 4, wiredata, 8, NULL, 0,  "up_ulong");
395     test_pointer_marshal(fmtstr_up_enum32, &l, 4, wiredata, 8, NULL, 0,  "up_emun32");
396     test_pointer_marshal(fmtstr_up_errorstatus, &l, 4, wiredata, 8, NULL, 0,  "up_errorstatus");
397
398     ll = ((ULONGLONG)0xcafebabe) << 32 | 0xdeadbeef;
399     *(void**)wiredata = &ll;
400     *(void**)(wiredata + sizeof(void*)) = NULL;
401     *(ULONGLONG*)(wiredata + 2 * sizeof(void*)) = ll;
402     test_pointer_marshal(fmtstr_up_longlong, &ll, 8, wiredata, 16, NULL, 0, "up_longlong");
403
404     f = 3.1415;
405     *(void**)wiredata = &f;
406     *(float*)(wiredata + sizeof(void*)) = f;
407     test_pointer_marshal(fmtstr_up_float, &f, 4, wiredata, 8, NULL, 0, "up_float");
408
409     d = 3.1415;
410     *(void**)wiredata = &d;
411     *(void**)(wiredata + sizeof(void*)) = NULL;
412     *(double*)(wiredata + 2 * sizeof(void*)) = d;
413     test_pointer_marshal(fmtstr_up_double, &d, 8, wiredata, 16, NULL, 0,  "up_double");
414
415 }
416
417 static void test_simple_struct_marshal(const unsigned char *formattypes,
418                                        void *memsrc,
419                                        long srcsize,
420                                        const void *wiredata,
421                                        long wiredatalen,
422                                        int(*cmp)(const void*,const void*,size_t),
423                                        long num_additional_allocs,
424                                        const char *msgpfx)
425 {
426     RPC_MESSAGE RpcMessage;
427     MIDL_STUB_MESSAGE StubMsg;
428     MIDL_STUB_DESC StubDesc;
429     DWORD size;
430     void *ptr;
431     unsigned char *mem, *mem_orig;
432
433     my_alloc_called = my_free_called = 0;
434     if(!cmp)
435         cmp = memcmp;
436
437     StubDesc = Object_StubDesc;
438     StubDesc.pFormatTypes = formattypes;
439
440     NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0);
441
442     StubMsg.BufferLength = 0;
443     NdrSimpleStructBufferSize( &StubMsg, (unsigned char *)memsrc, formattypes );
444     ok(StubMsg.BufferLength >= wiredatalen, "%s: length %ld\n", msgpfx, StubMsg.BufferLength);
445     StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
446     StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
447     ptr = NdrSimpleStructMarshall( &StubMsg,  (unsigned char*)memsrc, formattypes );
448     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
449     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
450     ok(!memcmp(StubMsg.BufferStart, wiredata, wiredatalen), "%s: incorrectly marshaled %08lx %08lx %08lx\n", msgpfx, *(DWORD*)StubMsg.BufferStart,*((DWORD*)StubMsg.BufferStart+1),*((DWORD*)StubMsg.BufferStart+2));
451
452 #if 0
453     StubMsg.Buffer = StubMsg.BufferStart;
454     StubMsg.MemorySize = 0;
455     size = NdrSimpleStructMemorySize( &StubMsg, formattypes );
456     ok(size == StubMsg.MemorySize, "%s: size != MemorySize\n", msgpfx);
457     ok(size == srcsize, "%s: mem size %ld\n", msgpfx, size);
458     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
459
460     StubMsg.Buffer = StubMsg.BufferStart;
461     size = NdrSimpleStructMemorySize( &StubMsg, formattypes );
462 todo_wine {
463     ok(size == StubMsg.MemorySize, "%s: size != MemorySize\n", msgpfx);
464 }
465     ok(StubMsg.MemorySize == ((srcsize + 3) & ~3) + srcsize, "%s: mem size %ld\n", msgpfx, size);
466     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
467 #endif
468     size = srcsize;
469     /*** Unmarshalling first with must_alloc false ***/
470
471     StubMsg.Buffer = StubMsg.BufferStart;
472     StubMsg.MemorySize = 0;
473     mem_orig = mem = HeapAlloc(GetProcessHeap(), 0, srcsize);
474     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 0 );
475     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
476     ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart);
477     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
478     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
479     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called); 
480     my_alloc_called = 0;
481     ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx);
482
483     /* if we're a server we still use the suppiled memory */
484     StubMsg.Buffer = StubMsg.BufferStart;
485     StubMsg.IsClient = 0;
486     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 0 );
487     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
488     ok(mem == mem_orig, "%s: mem has changed %p %p\n", msgpfx, mem, mem_orig);
489     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx); 
490     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
491     my_alloc_called = 0;
492     ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx);
493
494     /* ...unless we pass a NULL ptr, then the buffer is used. 
495        Passing a NULL ptr while we're a client && !must_alloc
496        crashes on Windows, so we won't do that. */
497
498     mem = NULL;
499     StubMsg.IsClient = 0;
500     StubMsg.Buffer = StubMsg.BufferStart;
501     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 0 );
502     ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr);
503     ok(mem == StubMsg.BufferStart, "%s: mem not equal buffer\n", msgpfx);
504     ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx);
505     ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
506     my_alloc_called = 0;
507     ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx);
508
509     /*** now must_alloc is true ***/
510
511     /* with must_alloc set we always allocate new memory whether or not we're
512        a server and also when passing NULL */
513     mem = mem_orig;
514     StubMsg.IsClient = 1;
515     StubMsg.Buffer = StubMsg.BufferStart;
516     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
517     ok(ptr == NULL, "ret %p\n", ptr);
518     ok(mem != mem_orig, "mem not changed %p %p\n", mem, mem_orig);
519     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n");
520     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
521     my_alloc_called = 0;
522     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
523
524     mem = NULL;
525     StubMsg.Buffer = StubMsg.BufferStart;
526     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
527     ok(ptr == NULL, "ret %p\n", ptr);
528     ok(mem != mem_orig, "mem not changed %p %p\n", mem, mem_orig);
529     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n");
530     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
531     my_alloc_called = 0; 
532     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
533
534     mem = mem_orig;
535     StubMsg.Buffer = StubMsg.BufferStart;
536     StubMsg.IsClient = 0;
537     StubMsg.ReuseBuffer = 1;
538     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
539     ok(ptr == NULL, "ret %p\n", ptr);
540     ok(mem != mem_orig, "mem not changed %p %p\n", mem, mem_orig);
541     ok(mem != StubMsg.BufferStart, "mem is buffer mem\n");
542     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n");
543     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
544     my_alloc_called = 0;
545     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
546
547     mem = NULL;
548     StubMsg.Buffer = StubMsg.BufferStart;
549     StubMsg.IsClient = 0;
550     StubMsg.ReuseBuffer = 1;
551     ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 1 );
552     ok(ptr == NULL, "ret %p\n", ptr);
553     ok(mem != StubMsg.BufferStart, "mem is buffer mem\n");
554     ok(!cmp(mem, memsrc, srcsize), "incorrectly unmarshaled\n"); 
555     ok(my_alloc_called == num_additional_allocs + 1, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called);
556     my_alloc_called = 0;
557     ok(StubMsg.MemorySize == 0, "memorysize touched in unmarshal\n");
558
559 }
560
561 typedef struct
562 {
563     long l1;
564     long *pl1;
565     char *pc1;
566 } ps1_t;
567
568 static int ps1_cmp(const void *s1, const void *s2, size_t num)
569 {
570     const ps1_t *p1, *p2;
571
572     p1 = s1;
573     p2 = s2;
574
575     if(p1->l1 != p2->l1)
576         return 1;
577
578     if(p1->pl1 && p2->pl1)
579     {
580         if(*p1->pl1 != *p2->pl1)
581             return 1;
582     }
583     else if(p1->pl1 || p1->pl1)
584         return 1;
585
586     if(p1->pc1 && p2->pc1)
587     {
588         if(*p1->pc1 != *p2->pc1)
589             return 1;
590     }
591     else if(p1->pc1 || p1->pc1)
592         return 1;
593
594     return 0;
595 }
596
597 static void test_simple_struct(void)
598 {
599     unsigned char wiredata[28];
600     unsigned long wiredatalen;
601     long l;
602     char c;
603     ps1_t ps1;
604
605     static const unsigned char fmtstr_simple_struct[] =
606     {
607         0x12, 0x0,      /* FC_UP */
608         NdrFcShort( 0x2 ), /* Offset=2 */
609         0x15, 0x3,      /* FC_STRUCT [align 4] */
610         NdrFcShort( 0x18 ),      /* [size 24] */
611         0x6,            /* FC_SHORT */
612         0x2,            /* FC_CHAR */ 
613         0x38,           /* FC_ALIGNM4 */
614         0x8,            /* FC_LONG */
615         0x8,            /* FC_LONG */
616         0x39,           /* FC_ALIGNM8 */
617         0xb,            /* FC_HYPER */ 
618         0x5b,           /* FC_END */
619     };
620     struct {
621         short s;
622         char c;
623         long l1, l2;
624         LONGLONG ll;
625     } s1;
626
627     static const unsigned char fmtstr_pointer_struct[] =
628     { 
629         0x12, 0x0,      /* FC_UP */
630         NdrFcShort( 0x2 ), /* Offset=2 */
631         0x16, 0x3,      /* FC_PSTRUCT [align 4] */
632         NdrFcShort( 0xc ),      /* [size 12] */
633         0x4b,           /* FC_PP */
634         0x5c,           /* FC_PAD */
635         0x46,           /* FC_NO_REPEAT */
636         0x5c,           /* FC_PAD */
637         NdrFcShort( 0x4 ),      /* 4 */
638         NdrFcShort( 0x4 ),      /* 4 */
639         0x13, 0x8,      /* FC_OP [simple_pointer] */
640         0x8,            /* FC_LONG */
641         0x5c,           /* FC_PAD */
642         0x46,           /* FC_NO_REPEAT */
643         0x5c,           /* FC_PAD */
644         NdrFcShort( 0x8 ),      /* 8 */
645         NdrFcShort( 0x8 ),      /* 8 */
646         0x13, 0x8,      /* FC_OP [simple_pointer] */
647         0x2,            /* FC_CHAR */
648         0x5c,           /* FC_PAD */
649         0x5b,           /* FC_END */
650         0x8,            /* FC_LONG */
651         0x8,            /* FC_LONG */
652         0x8,            /* FC_LONG */
653         0x5c,           /* FC_PAD */
654         0x5b,           /* FC_END */
655
656     };
657
658     /* FC_STRUCT */
659     s1.s = 0x1234;
660     s1.c = 0xa5;
661     s1.l1 = 0xdeadbeef;
662     s1.l2 = 0xcafebabe;
663     s1.ll = ((LONGLONG) 0xbadefeed << 32) || 0x2468ace0;
664
665     wiredatalen = 24;
666     memcpy(wiredata, &s1, wiredatalen); 
667     test_simple_struct_marshal(fmtstr_simple_struct + 4, &s1, 24, wiredata, 24, NULL, 0, "struct");
668
669     *(void**)wiredata = &s1;
670     memcpy(wiredata + 4, &s1, wiredatalen);
671 #if 0 /* one of the unmarshallings crashes Wine */
672     test_pointer_marshal(fmtstr_simple_struct, &s1, 24, wiredata, 28, NULL, 0, "struct");
673 #endif
674
675     /* FC_PSTRUCT */
676     ps1.l1 = 0xdeadbeef;
677     l = 0xcafebabe;
678     ps1.pl1 = &l;
679     c = 'a';
680     ps1.pc1 = &c;
681     memcpy(wiredata + 4, &ps1, 12);
682     memcpy(wiredata + 16, &l, 4);
683     memcpy(wiredata + 20, &c, 1);
684
685     test_simple_struct_marshal(fmtstr_pointer_struct + 4, &ps1, 17, wiredata + 4, 17, ps1_cmp, 2, "pointer_struct");
686     *(void**)wiredata = &ps1;
687 #if 0 /* one of the unmarshallings crashes Wine */
688     test_pointer_marshal(fmtstr_pointer_struct, &ps1, 17, wiredata, 21, ps1_cmp, 2, "pointer_struct");
689 #endif
690 }
691
692 static void test_fullpointer_xlat(void)
693 {
694     PFULL_PTR_XLAT_TABLES pXlatTables;
695     unsigned long RefId;
696     int ret;
697     void *Pointer;
698
699     pXlatTables = NdrFullPointerXlatInit(2, XLAT_CLIENT);
700
701     /* "marshaling" phase */
702
703     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 1, &RefId);
704     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
705     ok(RefId == 0x1, "RefId should be 0x1 instead of 0x%lx\n", RefId);
706
707     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 0, &RefId);
708     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
709     ok(RefId == 0x1, "RefId should be 0x1 instead of 0x%lx\n", RefId);
710
711     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebabe, 0, &RefId);
712     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
713     ok(RefId == 0x2, "RefId should be 0x2 instead of 0x%lx\n", RefId);
714
715     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xdeadbeef, 0, &RefId);
716     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
717     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%lx\n", RefId);
718
719     ret = NdrFullPointerQueryPointer(pXlatTables, NULL, 0, &RefId);
720     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
721     ok(RefId == 0, "RefId should be 0 instead of 0x%lx\n", RefId);
722
723     /* "unmarshaling" phase */
724
725     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 0, &Pointer);
726     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
727     ok(Pointer == (void *)0xcafebabe, "Pointer should be 0xcafebabe instead of %p\n", Pointer);
728
729     ret = NdrFullPointerQueryRefId(pXlatTables, 0x4, 0, &Pointer);
730     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
731     ok(Pointer == NULL, "Pointer should be NULL instead of %p\n", Pointer);
732
733     NdrFullPointerInsertRefId(pXlatTables, 0x4, (void *)0xdeadbabe);
734
735     ret = NdrFullPointerQueryRefId(pXlatTables, 0x4, 1, &Pointer);
736     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
737     ok(Pointer == (void *)0xdeadbabe, "Pointer should be (void *)0xdeadbabe instead of %p\n", Pointer);
738
739     NdrFullPointerXlatFree(pXlatTables);
740
741     pXlatTables = NdrFullPointerXlatInit(2, XLAT_SERVER);
742
743     /* "unmarshaling" phase */
744
745     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 1, &Pointer);
746     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
747     ok(Pointer == NULL, "Pointer should be NULL instead of %p\n", Pointer);
748
749     NdrFullPointerInsertRefId(pXlatTables, 0x2, (void *)0xcafebabe);
750
751     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 0, &Pointer);
752     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
753     ok(Pointer == (void *)0xcafebabe, "Pointer should be (void *)0xcafebabe instead of %p\n", Pointer);
754
755     ret = NdrFullPointerQueryRefId(pXlatTables, 0x2, 1, &Pointer);
756     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
757     ok(Pointer == (void *)0xcafebabe, "Pointer should be (void *)0xcafebabe instead of %p\n", Pointer);
758
759     /* "marshaling" phase */
760
761     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 1, &RefId);
762     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
763     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%lx\n", RefId);
764
765     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 1, &RefId);
766     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
767     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%lx\n", RefId);
768
769     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebeef, 0, &RefId);
770     todo_wine {
771     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
772     }
773     ok(RefId == 0x3, "RefId should be 0x3 instead of 0x%lx\n", RefId);
774
775     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xcafebabe, 0, &RefId);
776     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
777     ok(RefId == 0x2, "RefId should be 0x2 instead of 0x%lx\n", RefId);
778
779     ret = NdrFullPointerQueryPointer(pXlatTables, (void *)0xdeadbeef, 0, &RefId);
780     ok(ret == 0, "ret should be 0 instead of 0x%x\n", ret);
781     ok(RefId == 0x4, "RefId should be 0x4 instead of 0x%lx\n", RefId);
782
783     /* "freeing" phase */
784
785     ret = NdrFullPointerFree(pXlatTables, (void *)0xcafebeef);
786     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
787
788     ret = NdrFullPointerFree(pXlatTables, (void *)0xcafebabe);
789     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
790
791     ret = NdrFullPointerFree(pXlatTables, (void *)0xdeadbeef);
792     ok(ret == 1, "ret should be 1 instead of 0x%x\n", ret);
793
794     NdrFullPointerXlatFree(pXlatTables);
795 }
796
797 START_TEST( ndr_marshall )
798 {
799     test_simple_types();
800     test_simple_struct();
801     test_fullpointer_xlat();
802 }