hlink/tests: Sign compare fix.
[wine] / dlls / ole32 / tests / usrmarshal.c
1 /*
2  * User Marshaling Tests
3  *
4  * Copyright 2004-2006 Robert Shearman for CodeWeavers
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 COBJMACROS
22 #define CONST_VTABLE
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "objidl.h"
29
30 #include "wine/test.h"
31
32 ULONG __RPC_USER HMETAFILE_UserSize(ULONG *, unsigned long, HMETAFILE *);
33 unsigned char * __RPC_USER HMETAFILE_UserMarshal(ULONG *, unsigned char *, HMETAFILE *);
34 unsigned char * __RPC_USER HMETAFILE_UserUnmarshal(ULONG *, unsigned char *, HMETAFILE *);
35 void __RPC_USER HMETAFILE_UserFree(ULONG *, HMETAFILE *);
36
37 ULONG __RPC_USER HENHMETAFILE_UserSize(ULONG *, ULONG, HENHMETAFILE *);
38 unsigned char * __RPC_USER HENHMETAFILE_UserMarshal  (ULONG *, unsigned char *, HENHMETAFILE *);
39 unsigned char * __RPC_USER HENHMETAFILE_UserUnmarshal(ULONG *, unsigned char *, HENHMETAFILE *);
40 void  __RPC_USER HENHMETAFILE_UserFree(ULONG *, HENHMETAFILE *);
41
42 ULONG __RPC_USER HMETAFILEPICT_UserSize(ULONG *, ULONG, HMETAFILEPICT *);
43 unsigned char * __RPC_USER HMETAFILEPICT_UserMarshal  (ULONG *, unsigned char *, HMETAFILEPICT *);
44 unsigned char * __RPC_USER HMETAFILEPICT_UserUnmarshal(ULONG *, unsigned char *, HMETAFILEPICT *);
45 void __RPC_USER HMETAFILEPICT_UserFree(ULONG *, HMETAFILEPICT *);
46
47 static void * WINAPI user_allocate(SIZE_T size)
48 {
49     return CoTaskMemAlloc(size);
50 }
51
52 static void WINAPI user_free(void *p)
53 {
54     CoTaskMemFree(p);
55 }
56
57 static void init_user_marshal_cb(USER_MARSHAL_CB *umcb,
58                                  PMIDL_STUB_MESSAGE stub_msg,
59                                  PRPC_MESSAGE rpc_msg, unsigned char *buffer,
60                                  unsigned int size, MSHCTX context)
61 {
62     memset(rpc_msg, 0, sizeof(*rpc_msg));
63     rpc_msg->Buffer = buffer;
64     rpc_msg->BufferLength = size;
65
66     memset(stub_msg, 0, sizeof(*stub_msg));
67     stub_msg->RpcMsg = rpc_msg;
68     stub_msg->Buffer = buffer;
69     stub_msg->pfnAllocate = user_allocate;
70     stub_msg->pfnFree = user_free;
71
72     memset(umcb, 0, sizeof(*umcb));
73     umcb->Flags = MAKELONG(context, NDR_LOCAL_DATA_REPRESENTATION);
74     umcb->pStubMsg = stub_msg;
75     umcb->Signature = USER_MARSHAL_CB_SIGNATURE;
76     umcb->CBType = buffer ? USER_MARSHAL_CB_UNMARSHALL : USER_MARSHAL_CB_BUFFER_SIZE;
77 }
78
79 static const char cf_marshaled[] =
80 {
81     0x9, 0x0, 0x0, 0x0,
82     0x0, 0x0, 0x0, 0x0,
83     0x9, 0x0, 0x0, 0x0,
84     'M', 0x0, 'y', 0x0,
85     'F', 0x0, 'o', 0x0,
86     'r', 0x0, 'm', 0x0,
87     'a', 0x0, 't', 0x0,
88     0x0, 0x0
89 };
90
91 static void test_marshal_CLIPFORMAT(void)
92 {
93     USER_MARSHAL_CB umcb;
94     MIDL_STUB_MESSAGE stub_msg;
95     RPC_MESSAGE rpc_msg;
96     unsigned char *buffer;
97     ULONG i, size;
98     CLIPFORMAT cf = RegisterClipboardFormatA("MyFormat");
99     CLIPFORMAT cf2;
100
101     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
102     size = CLIPFORMAT_UserSize(&umcb.Flags, 0, &cf);
103     ok(size == 8 + sizeof(cf_marshaled) ||
104        broken(size == 12 + sizeof(cf_marshaled)) ||  /* win64 adds 4 extra (unused) bytes */
105        broken(size == 8 + sizeof(cf_marshaled) - 2), /* win9x and winnt don't include the '\0' */
106               "CLIPFORMAT: Wrong size %d\n", size);
107
108     buffer = HeapAlloc(GetProcessHeap(), 0, size);
109     memset( buffer, 0xcc, size );
110     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
111     CLIPFORMAT_UserMarshal(&umcb.Flags, buffer, &cf);
112     ok(*(LONG *)(buffer + 0) == WDT_REMOTE_CALL, "CLIPFORMAT: Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(LONG *)(buffer + 0));
113     ok(*(DWORD *)(buffer + 4) == cf, "CLIPFORMAT: Marshaled value should be 0x%04x instead of 0x%04x\n", cf, *(DWORD *)(buffer + 4));
114     ok(!memcmp(buffer + 8, cf_marshaled, min( sizeof(cf_marshaled), size-8 )), "Marshaled data differs\n");
115     if (size > sizeof(cf_marshaled) + 8)  /* make sure the extra bytes are not used */
116         for (i = sizeof(cf_marshaled) + 8; i < size; i++)
117             ok( buffer[i] == 0xcc, "buffer offset %u has been set to %x\n", i, buffer[i] );
118
119     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
120     CLIPFORMAT_UserUnmarshal(&umcb.Flags, buffer, &cf2);
121     ok(cf == cf2, "CLIPFORMAT: Didn't unmarshal properly\n");
122     HeapFree(GetProcessHeap(), 0, buffer);
123
124     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
125     CLIPFORMAT_UserFree(&umcb.Flags, &cf2);
126 }
127
128 static void test_marshal_HWND(void)
129 {
130     USER_MARSHAL_CB umcb;
131     MIDL_STUB_MESSAGE stub_msg;
132     RPC_MESSAGE rpc_msg;
133     unsigned char *buffer;
134     ULONG size;
135     HWND hwnd = GetDesktopWindow();
136     HWND hwnd2;
137     wireHWND wirehwnd;
138
139     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
140     size = HWND_UserSize(&umcb.Flags, 0, &hwnd);
141     ok(size == sizeof(*wirehwnd), "Wrong size %d\n", size);
142
143     buffer = HeapAlloc(GetProcessHeap(), 0, size);
144     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
145     HWND_UserMarshal(&umcb.Flags, buffer, &hwnd);
146     wirehwnd = (wireHWND)buffer;
147     ok(wirehwnd->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehwnd->fContext);
148     ok(wirehwnd->u.hInproc == (LONG_PTR)hwnd, "Marshaled value should be %p instead of %p\n", hwnd, (HANDLE)wirehwnd->u.hRemote);
149
150     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
151     HWND_UserUnmarshal(&umcb.Flags, buffer, &hwnd2);
152     ok(hwnd == hwnd2, "Didn't unmarshal properly\n");
153     HeapFree(GetProcessHeap(), 0, buffer);
154
155     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
156     HWND_UserFree(&umcb.Flags, &hwnd2);
157 }
158
159 static void test_marshal_HGLOBAL(void)
160 {
161     USER_MARSHAL_CB umcb;
162     MIDL_STUB_MESSAGE stub_msg;
163     RPC_MESSAGE rpc_msg;
164     unsigned char *buffer;
165     ULONG size;
166     HGLOBAL hglobal;
167     HGLOBAL hglobal2;
168     unsigned char *wirehglobal;
169     int i;
170
171     hglobal = NULL;
172     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
173     size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal);
174     /* native is poorly programmed and allocates 4/8 bytes more than it needs to
175      * here - Wine doesn't have to emulate that */
176     ok((size == 8) || broken(size == 12) || broken(size == 16), "Size should be 8, instead of %d\n", size);
177     buffer = HeapAlloc(GetProcessHeap(), 0, size);
178     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
179     HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal);
180     wirehglobal = buffer;
181     ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal);
182     wirehglobal += sizeof(ULONG);
183     ok(*(ULONG *)wirehglobal == 0, "buffer+4 should be HGLOBAL\n");
184     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
185     HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2);
186     ok(hglobal2 == hglobal, "Didn't unmarshal properly\n");
187     HeapFree(GetProcessHeap(), 0, buffer);
188     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
189     HGLOBAL_UserFree(&umcb.Flags, &hglobal2);
190
191     hglobal = GlobalAlloc(0, 4);
192     buffer = GlobalLock(hglobal);
193     for (i = 0; i < 4; i++)
194         buffer[i] = i;
195     GlobalUnlock(hglobal);
196     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
197     size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal);
198     /* native is poorly programmed and allocates 4/8 bytes more than it needs to
199      * here - Wine doesn't have to emulate that */
200     ok((size == 24) || broken(size == 28) || broken(size == 32), "Size should be 24, instead of %d\n", size);
201     buffer = HeapAlloc(GetProcessHeap(), 0, size);
202     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
203     HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal);
204     wirehglobal = buffer;
205     ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal);
206     wirehglobal += sizeof(ULONG);
207     ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0x4 should be HGLOBAL\n");
208     wirehglobal += sizeof(ULONG);
209     ok(*(ULONG *)wirehglobal == 4, "buffer+0x8 should be size of HGLOBAL instead of %d\n", *(ULONG *)wirehglobal);
210     wirehglobal += sizeof(ULONG);
211     ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0xc should be HGLOBAL\n");
212     wirehglobal += sizeof(ULONG);
213     ok(*(ULONG *)wirehglobal == 4, "buffer+0x10 should be size of HGLOBAL instead of %d\n", *(ULONG *)wirehglobal);
214     wirehglobal += sizeof(ULONG);
215     for (i = 0; i < 4; i++)
216         ok(wirehglobal[i] == i, "buffer+0x%x should be %d\n", 0x10 + i, i);
217     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
218     HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2);
219     ok(hglobal2 != NULL, "Didn't unmarshal properly\n");
220     HeapFree(GetProcessHeap(), 0, buffer);
221     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
222     HGLOBAL_UserFree(&umcb.Flags, &hglobal2);
223     GlobalFree(hglobal);
224 }
225
226 static HENHMETAFILE create_emf(void)
227 {
228     const RECT rect = {0, 0, 100, 100};
229     HDC hdc = CreateEnhMetaFile(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
230     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
231     return CloseEnhMetaFile(hdc);
232 }
233
234 static void test_marshal_HENHMETAFILE(void)
235 {
236     USER_MARSHAL_CB umcb;
237     MIDL_STUB_MESSAGE stub_msg;
238     RPC_MESSAGE rpc_msg;
239     unsigned char *buffer;
240     ULONG size;
241     HENHMETAFILE hemf;
242     HENHMETAFILE hemf2 = NULL;
243     unsigned char *wirehemf;
244
245     hemf = create_emf();
246
247     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
248     size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf);
249     ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
250     buffer = HeapAlloc(GetProcessHeap(), 0, size);
251     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
252     HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf);
253     wirehemf = buffer;
254     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
255     wirehemf += sizeof(DWORD);
256     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
257     wirehemf += sizeof(DWORD);
258     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf);
259     wirehemf += sizeof(DWORD);
260     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf);
261     wirehemf += sizeof(DWORD);
262     ok(*(DWORD *)wirehemf == EMR_HEADER, "wirestgm + 0x10 should be EMR_HEADER instead of %d\n", *(DWORD *)wirehemf);
263     wirehemf += sizeof(DWORD);
264     /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits
265      * at this point */
266
267     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
268     HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2);
269     ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n");
270     HeapFree(GetProcessHeap(), 0, buffer);
271     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
272     HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
273     DeleteEnhMetaFile(hemf);
274
275     /* test NULL emf */
276     hemf = NULL;
277
278     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
279     size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf);
280     ok(size == 8, "size should be 8 bytes, not %d\n", size);
281     buffer = HeapAlloc(GetProcessHeap(), 0, size);
282     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
283     HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf);
284     wirehemf = buffer;
285     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
286     wirehemf += sizeof(DWORD);
287     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
288     wirehemf += sizeof(DWORD);
289
290     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
291     HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2);
292     ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n");
293     HeapFree(GetProcessHeap(), 0, buffer);
294     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
295     HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
296 }
297
298 static HMETAFILE create_mf(void)
299 {
300     RECT rect = {0, 0, 100, 100};
301     HDC hdc = CreateMetaFile(NULL);
302     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
303     return CloseMetaFile(hdc);
304 }
305
306 static void test_marshal_HMETAFILE(void)
307 {
308     USER_MARSHAL_CB umcb;
309     MIDL_STUB_MESSAGE stub_msg;
310     RPC_MESSAGE rpc_msg;
311     unsigned char *buffer;
312     ULONG size;
313     HMETAFILE hmf;
314     HMETAFILE hmf2 = NULL;
315     unsigned char *wirehmf;
316
317     hmf = create_mf();
318
319     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
320     size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
321     ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
322     buffer = HeapAlloc(GetProcessHeap(), 0, size);
323     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
324     HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
325     wirehmf = buffer;
326     ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
327     wirehmf += sizeof(DWORD);
328     ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
329     wirehmf += sizeof(DWORD);
330     ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
331     wirehmf += sizeof(DWORD);
332     ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
333     wirehmf += sizeof(DWORD);
334     ok(*(WORD *)wirehmf == 1, "wirestgm + 0x10 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmf);
335     wirehmf += sizeof(DWORD);
336     /* ... rest of data not tested - refer to tests for GetMetaFileBits
337      * at this point */
338
339     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
340     HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
341     ok(hmf2 != NULL, "HMETAFILE didn't unmarshal\n");
342     HeapFree(GetProcessHeap(), 0, buffer);
343     HMETAFILE_UserFree(&umcb.Flags, &hmf2);
344     DeleteMetaFile(hmf);
345
346     /* test NULL emf */
347     hmf = NULL;
348
349     size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
350     ok(size == 8, "size should be 8 bytes, not %d\n", size);
351     buffer = HeapAlloc(GetProcessHeap(), 0, size);
352     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
353     HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
354     wirehmf = buffer;
355     ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
356     wirehmf += sizeof(DWORD);
357     ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
358     wirehmf += sizeof(DWORD);
359
360     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
361     HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
362     ok(hmf2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
363     HeapFree(GetProcessHeap(), 0, buffer);
364     HMETAFILE_UserFree(&umcb.Flags, &hmf2);
365 }
366
367 #define USER_MARSHAL_PTR_PREFIX \
368   ( (DWORD)'U'         | ( (DWORD)'s' << 8 ) | \
369   ( (DWORD)'e' << 16 ) | ( (DWORD)'r' << 24 ) )
370
371 static void test_marshal_HMETAFILEPICT(void)
372 {
373     USER_MARSHAL_CB umcb;
374     MIDL_STUB_MESSAGE stub_msg;
375     RPC_MESSAGE rpc_msg;
376     unsigned char *buffer, *buffer_end;
377     ULONG size;
378     HMETAFILEPICT hmfp;
379     HMETAFILEPICT hmfp2 = NULL;
380     METAFILEPICT *pmfp;
381     unsigned char *wirehmfp;
382
383     hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(*pmfp));
384     pmfp = GlobalLock(hmfp);
385     pmfp->mm = MM_ISOTROPIC;
386     pmfp->xExt = 1;
387     pmfp->yExt = 2;
388     pmfp->hMF = create_mf();
389     GlobalUnlock(hmfp);
390
391     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
392     size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp);
393     ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
394     trace("size is %d\n", size);
395     buffer = HeapAlloc(GetProcessHeap(), 0, size);
396     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
397     buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp);
398     wirehmfp = buffer;
399     ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
400     wirehmfp += sizeof(DWORD);
401     ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
402     wirehmfp += sizeof(DWORD);
403     ok(*(DWORD *)wirehmfp == MM_ISOTROPIC, "wirestgm + 0x8 should be MM_ISOTROPIC instead of 0x%08x\n", *(DWORD *)wirehmfp);
404     wirehmfp += sizeof(DWORD);
405     ok(*(DWORD *)wirehmfp == 1, "wirestgm + 0xc should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
406     wirehmfp += sizeof(DWORD);
407     ok(*(DWORD *)wirehmfp == 2, "wirestgm + 0x10 should be 2 instead of 0x%08x\n", *(DWORD *)wirehmfp);
408     wirehmfp += sizeof(DWORD);
409     ok(*(DWORD *)wirehmfp == USER_MARSHAL_PTR_PREFIX, "wirestgm + 0x14 should be \"User\" instead of 0x%08x\n", *(DWORD *)wirehmfp);
410     wirehmfp += sizeof(DWORD);
411     ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x18 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
412     wirehmfp += sizeof(DWORD);
413     pmfp = GlobalLock(hmfp);
414     ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)pmfp->hMF, "wirestgm + 0x1c should be pmfp->hMF instead of 0x%08x\n", *(DWORD *)wirehmfp);
415     GlobalUnlock(hmfp);
416     wirehmfp += sizeof(DWORD);
417     /* Note use (buffer_end - buffer) instead of size here, because size is an
418      * overestimate with native */
419     ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x20 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
420     wirehmfp += sizeof(DWORD);
421     ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x24 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
422     wirehmfp += sizeof(DWORD);
423     ok(*(WORD *)wirehmfp == 1, "wirehmfp + 0x28 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
424     wirehmfp += sizeof(DWORD);
425     /* ... rest of data not tested - refer to tests for GetMetaFileBits
426      * at this point */
427
428     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
429     HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2);
430     ok(hmfp2 != NULL, "HMETAFILEPICT didn't unmarshal\n");
431     HeapFree(GetProcessHeap(), 0, buffer);
432     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
433     HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
434     pmfp = GlobalLock(hmfp);
435     DeleteMetaFile(pmfp->hMF);
436     GlobalUnlock(hmfp);
437     GlobalFree(hmfp);
438
439     /* test NULL emf */
440     hmfp = NULL;
441
442     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
443     size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp);
444     ok(size == 8, "size should be 8 bytes, not %d\n", size);
445     buffer = HeapAlloc(GetProcessHeap(), 0, size);
446     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
447     HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp);
448     wirehmfp = buffer;
449     ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
450     wirehmfp += sizeof(DWORD);
451     ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
452     wirehmfp += sizeof(DWORD);
453
454     hmfp2 = NULL;
455     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
456     HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2);
457     ok(hmfp2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
458     HeapFree(GetProcessHeap(), 0, buffer);
459     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
460     HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
461 }
462
463 static HRESULT WINAPI Test_IUnknown_QueryInterface(
464                                                    LPUNKNOWN iface,
465                                                    REFIID riid,
466                                                    LPVOID *ppvObj)
467 {
468     if (ppvObj == NULL) return E_POINTER;
469
470     if (IsEqualGUID(riid, &IID_IUnknown))
471     {
472         *ppvObj = iface;
473         IUnknown_AddRef(iface);
474         return S_OK;
475     }
476
477     *ppvObj = NULL;
478     return E_NOINTERFACE;
479 }
480
481 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
482 {
483     return 2; /* non-heap-based object */
484 }
485
486 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
487 {
488     return 1; /* non-heap-based object */
489 }
490
491 static const IUnknownVtbl TestUnknown_Vtbl =
492 {
493     Test_IUnknown_QueryInterface,
494     Test_IUnknown_AddRef,
495     Test_IUnknown_Release,
496 };
497
498 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
499
500 ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG *, ULONG, ULONG, IUnknown *, REFIID);
501 unsigned char * __RPC_USER WdtpInterfacePointer_UserMarshal(ULONG *, ULONG, unsigned char *, IUnknown *, REFIID);
502 unsigned char * __RPC_USER WdtpInterfacePointer_UserUnmarshal(ULONG *, unsigned char *, IUnknown **, REFIID);
503 void __RPC_USER WdtpInterfacePointer_UserFree(IUnknown *);
504
505 static void test_marshal_WdtpInterfacePointer(void)
506 {
507     USER_MARSHAL_CB umcb;
508     MIDL_STUB_MESSAGE stub_msg;
509     RPC_MESSAGE rpc_msg;
510     unsigned char *buffer, *buffer_end;
511     ULONG size;
512     IUnknown *unk;
513     IUnknown *unk2;
514     unsigned char *wireip;
515     const IID *iid;
516
517     /* shows that the WdtpInterfacePointer functions don't marshal anything for
518      * NULL pointers, so code using these functions must handle that case
519      * itself */
520     unk = NULL;
521     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
522     size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 0, unk, &IID_IUnknown);
523     ok(size == 0, "size should be 0 bytes, not %d\n", size);
524     buffer = HeapAlloc(GetProcessHeap(), 0, size);
525     buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, buffer, unk, &IID_IUnknown);
526     wireip = buffer;
527     HeapFree(GetProcessHeap(), 0, buffer);
528
529     unk = &Test_Unknown;
530     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
531     size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 0, unk, &IID_IUnknown);
532     todo_wine
533     ok(size > 28, "size should be > 28 bytes, not %d\n", size);
534     trace("WdtpInterfacePointer_UserSize returned %d\n", size);
535     buffer = HeapAlloc(GetProcessHeap(), 0, size);
536     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC);
537     buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, buffer, unk, &IID_IUnknown);
538     wireip = buffer;
539     if (size >= 28)
540     {
541         ok(*(DWORD *)wireip == 0x44, "wireip + 0x0 should be 0x44 instead of 0x%08x\n", *(DWORD *)wireip);
542         wireip += sizeof(DWORD);
543         ok(*(DWORD *)wireip == 0x44, "wireip + 0x4 should be 0x44 instead of 0x%08x\n", *(DWORD *)wireip);
544         wireip += sizeof(DWORD);
545         ok(*(DWORD *)wireip == 0x574f454d /* 'MEOW' */, "wireip + 0x8 should be 0x574f454d instead of 0x%08x\n", *(DWORD *)wireip);
546         wireip += sizeof(DWORD);
547         ok(*(DWORD *)wireip == 0x1, "wireip + 0xc should be 0x1 instead of 0x%08x\n", *(DWORD *)wireip);
548         wireip += sizeof(DWORD);
549         iid = (const IID *)wireip;
550         ok(IsEqualIID(iid, &IID_IUnknown),
551            "wireip + 0x10 should be IID_IUnknown instead of {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
552            iid->Data1, iid->Data2, iid->Data3,
553            iid->Data4[0], iid->Data4[1], iid->Data4[2], iid->Data4[3],
554            iid->Data4[4], iid->Data4[5], iid->Data4[6], iid->Data4[7]);
555         wireip += sizeof(IID);
556         ok(*(DWORD *)wireip == 0, "wireip + 0x1c should be 0 instead of 0x%08x\n", *(DWORD *)wireip);
557         wireip += sizeof(DWORD);
558         ok(*(DWORD *)wireip == 5, "wireip + 0x20 should be 5 instead of %d\n", *(DWORD *)wireip);
559         wireip += sizeof(DWORD);
560         /* the rest is dynamic so can't really be tested */
561     }
562
563     unk2 = NULL;
564     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC);
565     WdtpInterfacePointer_UserUnmarshal(&umcb.Flags, buffer, &unk2, &IID_IUnknown);
566     todo_wine
567     ok(unk2 != NULL, "IUnknown object didn't unmarshal properly\n");
568     HeapFree(GetProcessHeap(), 0, buffer);
569     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
570     WdtpInterfacePointer_UserFree(unk2);
571 }
572
573 START_TEST(usrmarshal)
574 {
575     CoInitialize(NULL);
576
577     test_marshal_CLIPFORMAT();
578     test_marshal_HWND();
579     test_marshal_HGLOBAL();
580     test_marshal_HENHMETAFILE();
581     test_marshal_HMETAFILE();
582     test_marshal_HMETAFILEPICT();
583     test_marshal_WdtpInterfacePointer();
584
585     CoUninitialize();
586 }