riched20: Use ME_PointFromChar to calculate the caret position.
[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 *, ULONG, 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 %x\n", hwnd, 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, block_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     hglobal2 = NULL;
186     HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2);
187     ok(hglobal2 == hglobal, "Didn't unmarshal properly\n");
188     HeapFree(GetProcessHeap(), 0, buffer);
189     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
190     HGLOBAL_UserFree(&umcb.Flags, &hglobal2);
191
192
193     for(block_size = 0; block_size <= 17; block_size++)
194     {
195         ULONG actual_size, expected_size;
196
197         hglobal = GlobalAlloc(0, block_size);
198         buffer = GlobalLock(hglobal);
199         for (i = 0; i < block_size; i++)
200             buffer[i] = i;
201         GlobalUnlock(hglobal);
202         actual_size = GlobalSize(hglobal);
203         expected_size = actual_size + 5 * sizeof(DWORD);
204         trace("%d: actual size %d\n", block_size, actual_size);
205         init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
206         size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal);
207         /* native is poorly programmed and allocates 4/8 bytes more than it needs to
208          * here - Wine doesn't have to emulate that */
209         ok(size == expected_size ||
210            broken(size == expected_size + 4) ||
211            broken(size == expected_size + 8),
212            "%d: got size %d\n", block_size, size);
213         buffer = HeapAlloc(GetProcessHeap(), 0, size);
214         init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
215         HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal);
216         wirehglobal = buffer;
217         ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal);
218         wirehglobal += sizeof(ULONG);
219         ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0x4 should be HGLOBAL\n");
220         wirehglobal += sizeof(ULONG);
221         ok(*(ULONG *)wirehglobal == actual_size, "%d: buffer+0x8 %08x\n", block_size, *(ULONG *)wirehglobal);
222         wirehglobal += sizeof(ULONG);
223         ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0xc should be HGLOBAL\n");
224         wirehglobal += sizeof(ULONG);
225         ok(*(ULONG *)wirehglobal == actual_size, "%d: buffer+0x10 %08x\n", block_size, *(ULONG *)wirehglobal);
226         wirehglobal += sizeof(ULONG);
227         for (i = 0; i < block_size; i++)
228             ok(wirehglobal[i] == i, "buffer+0x%x should be %d\n", 0x10 + i, i);
229
230         init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
231         hglobal2 = NULL;
232         HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2);
233         ok(hglobal2 != NULL, "Didn't unmarshal properly\n");
234         HeapFree(GetProcessHeap(), 0, buffer);
235         init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
236         HGLOBAL_UserFree(&umcb.Flags, &hglobal2);
237         GlobalFree(hglobal);
238     }
239 }
240
241 static HENHMETAFILE create_emf(void)
242 {
243     const RECT rect = {0, 0, 100, 100};
244     HDC hdc = CreateEnhMetaFile(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
245     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
246     return CloseEnhMetaFile(hdc);
247 }
248
249 static void test_marshal_HENHMETAFILE(void)
250 {
251     USER_MARSHAL_CB umcb;
252     MIDL_STUB_MESSAGE stub_msg;
253     RPC_MESSAGE rpc_msg;
254     unsigned char *buffer;
255     ULONG size;
256     HENHMETAFILE hemf;
257     HENHMETAFILE hemf2 = NULL;
258     unsigned char *wirehemf;
259
260     hemf = create_emf();
261
262     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
263     size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf);
264     ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
265     buffer = HeapAlloc(GetProcessHeap(), 0, size);
266     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
267     HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf);
268     wirehemf = buffer;
269     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
270     wirehemf += sizeof(DWORD);
271     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
272     wirehemf += sizeof(DWORD);
273     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf);
274     wirehemf += sizeof(DWORD);
275     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf);
276     wirehemf += sizeof(DWORD);
277     ok(*(DWORD *)wirehemf == EMR_HEADER, "wirestgm + 0x10 should be EMR_HEADER instead of %d\n", *(DWORD *)wirehemf);
278     wirehemf += sizeof(DWORD);
279     /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits
280      * at this point */
281
282     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
283     HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2);
284     ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n");
285     HeapFree(GetProcessHeap(), 0, buffer);
286     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
287     HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
288     DeleteEnhMetaFile(hemf);
289
290     /* test NULL emf */
291     hemf = NULL;
292
293     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
294     size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf);
295     ok(size == 8, "size should be 8 bytes, not %d\n", size);
296     buffer = HeapAlloc(GetProcessHeap(), 0, size);
297     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
298     HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf);
299     wirehemf = buffer;
300     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
301     wirehemf += sizeof(DWORD);
302     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
303     wirehemf += sizeof(DWORD);
304
305     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
306     HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2);
307     ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n");
308     HeapFree(GetProcessHeap(), 0, buffer);
309     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
310     HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
311 }
312
313 static HMETAFILE create_mf(void)
314 {
315     RECT rect = {0, 0, 100, 100};
316     HDC hdc = CreateMetaFile(NULL);
317     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
318     return CloseMetaFile(hdc);
319 }
320
321 static void test_marshal_HMETAFILE(void)
322 {
323     USER_MARSHAL_CB umcb;
324     MIDL_STUB_MESSAGE stub_msg;
325     RPC_MESSAGE rpc_msg;
326     unsigned char *buffer;
327     ULONG size;
328     HMETAFILE hmf;
329     HMETAFILE hmf2 = NULL;
330     unsigned char *wirehmf;
331
332     hmf = create_mf();
333
334     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
335     size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
336     ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
337     buffer = HeapAlloc(GetProcessHeap(), 0, size);
338     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
339     HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
340     wirehmf = buffer;
341     ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
342     wirehmf += sizeof(DWORD);
343     ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
344     wirehmf += sizeof(DWORD);
345     ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
346     wirehmf += sizeof(DWORD);
347     ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
348     wirehmf += sizeof(DWORD);
349     ok(*(WORD *)wirehmf == 1, "wirestgm + 0x10 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmf);
350     wirehmf += sizeof(DWORD);
351     /* ... rest of data not tested - refer to tests for GetMetaFileBits
352      * at this point */
353
354     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
355     HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
356     ok(hmf2 != NULL, "HMETAFILE didn't unmarshal\n");
357     HeapFree(GetProcessHeap(), 0, buffer);
358     HMETAFILE_UserFree(&umcb.Flags, &hmf2);
359     DeleteMetaFile(hmf);
360
361     /* test NULL emf */
362     hmf = NULL;
363
364     size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
365     ok(size == 8, "size should be 8 bytes, not %d\n", size);
366     buffer = HeapAlloc(GetProcessHeap(), 0, size);
367     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
368     HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
369     wirehmf = buffer;
370     ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
371     wirehmf += sizeof(DWORD);
372     ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
373     wirehmf += sizeof(DWORD);
374
375     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
376     HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
377     ok(hmf2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
378     HeapFree(GetProcessHeap(), 0, buffer);
379     HMETAFILE_UserFree(&umcb.Flags, &hmf2);
380 }
381
382 #define USER_MARSHAL_PTR_PREFIX \
383   ( (DWORD)'U'         | ( (DWORD)'s' << 8 ) | \
384   ( (DWORD)'e' << 16 ) | ( (DWORD)'r' << 24 ) )
385
386 static void test_marshal_HMETAFILEPICT(void)
387 {
388     USER_MARSHAL_CB umcb;
389     MIDL_STUB_MESSAGE stub_msg;
390     RPC_MESSAGE rpc_msg;
391     unsigned char *buffer, *buffer_end;
392     ULONG size;
393     HMETAFILEPICT hmfp;
394     HMETAFILEPICT hmfp2 = NULL;
395     METAFILEPICT *pmfp;
396     unsigned char *wirehmfp;
397
398     hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(*pmfp));
399     pmfp = GlobalLock(hmfp);
400     pmfp->mm = MM_ISOTROPIC;
401     pmfp->xExt = 1;
402     pmfp->yExt = 2;
403     pmfp->hMF = create_mf();
404     GlobalUnlock(hmfp);
405
406     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
407     size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp);
408     ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
409     trace("size is %d\n", size);
410     buffer = HeapAlloc(GetProcessHeap(), 0, size);
411     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
412     buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp);
413     wirehmfp = buffer;
414     ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
415     wirehmfp += sizeof(DWORD);
416     ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
417     wirehmfp += sizeof(DWORD);
418     ok(*(DWORD *)wirehmfp == MM_ISOTROPIC, "wirestgm + 0x8 should be MM_ISOTROPIC instead of 0x%08x\n", *(DWORD *)wirehmfp);
419     wirehmfp += sizeof(DWORD);
420     ok(*(DWORD *)wirehmfp == 1, "wirestgm + 0xc should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
421     wirehmfp += sizeof(DWORD);
422     ok(*(DWORD *)wirehmfp == 2, "wirestgm + 0x10 should be 2 instead of 0x%08x\n", *(DWORD *)wirehmfp);
423     wirehmfp += sizeof(DWORD);
424     ok(*(DWORD *)wirehmfp == USER_MARSHAL_PTR_PREFIX, "wirestgm + 0x14 should be \"User\" instead of 0x%08x\n", *(DWORD *)wirehmfp);
425     wirehmfp += sizeof(DWORD);
426     ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x18 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
427     wirehmfp += sizeof(DWORD);
428     pmfp = GlobalLock(hmfp);
429     ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)pmfp->hMF, "wirestgm + 0x1c should be pmfp->hMF instead of 0x%08x\n", *(DWORD *)wirehmfp);
430     GlobalUnlock(hmfp);
431     wirehmfp += sizeof(DWORD);
432     /* Note use (buffer_end - buffer) instead of size here, because size is an
433      * overestimate with native */
434     ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x20 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
435     wirehmfp += sizeof(DWORD);
436     ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x24 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
437     wirehmfp += sizeof(DWORD);
438     ok(*(WORD *)wirehmfp == 1, "wirehmfp + 0x28 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
439     wirehmfp += sizeof(DWORD);
440     /* ... rest of data not tested - refer to tests for GetMetaFileBits
441      * at this point */
442
443     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
444     HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2);
445     ok(hmfp2 != NULL, "HMETAFILEPICT didn't unmarshal\n");
446     HeapFree(GetProcessHeap(), 0, buffer);
447     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
448     HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
449     pmfp = GlobalLock(hmfp);
450     DeleteMetaFile(pmfp->hMF);
451     GlobalUnlock(hmfp);
452     GlobalFree(hmfp);
453
454     /* test NULL emf */
455     hmfp = NULL;
456
457     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
458     size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp);
459     ok(size == 8, "size should be 8 bytes, not %d\n", size);
460     buffer = HeapAlloc(GetProcessHeap(), 0, size);
461     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
462     HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp);
463     wirehmfp = buffer;
464     ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
465     wirehmfp += sizeof(DWORD);
466     ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
467     wirehmfp += sizeof(DWORD);
468
469     hmfp2 = NULL;
470     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
471     HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2);
472     ok(hmfp2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
473     HeapFree(GetProcessHeap(), 0, buffer);
474     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
475     HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
476 }
477
478 static HRESULT WINAPI Test_IUnknown_QueryInterface(
479                                                    LPUNKNOWN iface,
480                                                    REFIID riid,
481                                                    LPVOID *ppvObj)
482 {
483     if (ppvObj == NULL) return E_POINTER;
484
485     if (IsEqualGUID(riid, &IID_IUnknown))
486     {
487         *ppvObj = iface;
488         IUnknown_AddRef(iface);
489         return S_OK;
490     }
491
492     *ppvObj = NULL;
493     return E_NOINTERFACE;
494 }
495
496 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
497 {
498     return 2; /* non-heap-based object */
499 }
500
501 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
502 {
503     return 1; /* non-heap-based object */
504 }
505
506 static const IUnknownVtbl TestUnknown_Vtbl =
507 {
508     Test_IUnknown_QueryInterface,
509     Test_IUnknown_AddRef,
510     Test_IUnknown_Release,
511 };
512
513 static HRESULT WINAPI Test_IStream_QueryInterface(IStream *iface,
514                                                   REFIID riid, LPVOID *ppvObj)
515 {
516     if (ppvObj == NULL) return E_POINTER;
517
518     if (IsEqualIID(riid, &IID_IUnknown) ||
519         IsEqualIID(riid, &IID_IStream))
520     {
521         *ppvObj = iface;
522         IStream_AddRef(iface);
523         return S_OK;
524     }
525
526     *ppvObj = NULL;
527     return E_NOINTERFACE;
528 }
529
530 static ULONG WINAPI Test_IStream_AddRef(IStream *iface)
531 {
532     return 2; /* non-heap-based object */
533 }
534
535 static ULONG WINAPI Test_IStream_Release(IStream *iface)
536 {
537     return 1; /* non-heap-based object */
538 }
539
540 static const IStreamVtbl TestStream_Vtbl =
541 {
542     Test_IStream_QueryInterface,
543     Test_IStream_AddRef,
544     Test_IStream_Release
545     /* the rest can be NULLs */
546 };
547
548 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
549 static IStream Test_Stream = { &TestStream_Vtbl };
550
551 ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG *, ULONG, ULONG, IUnknown *, REFIID);
552 unsigned char * __RPC_USER WdtpInterfacePointer_UserMarshal(ULONG *, ULONG, unsigned char *, IUnknown *, REFIID);
553 unsigned char * __RPC_USER WdtpInterfacePointer_UserUnmarshal(ULONG *, unsigned char *, IUnknown **, REFIID);
554
555 static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx)
556 {
557     USER_MARSHAL_CB umcb;
558     MIDL_STUB_MESSAGE stub_msg;
559     RPC_MESSAGE rpc_msg;
560     unsigned char *buffer, *buffer_end;
561     ULONG size;
562     IUnknown *unk;
563     IUnknown *unk2;
564     unsigned char *wireip;
565     HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, 0);
566     IStream *stm;
567     void *marshal_data;
568     LARGE_INTEGER zero;
569     ULARGE_INTEGER pos;
570     DWORD marshal_size;
571
572     /* shows that the WdtpInterfacePointer functions don't marshal anything for
573      * NULL pointers, so code using these functions must handle that case
574      * itself */
575
576     unk = NULL;
577     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, umcb_ctx);
578     size = WdtpInterfacePointer_UserSize(&umcb.Flags, ctx, 0, unk, &IID_IUnknown);
579     ok(size == 0, "size should be 0 bytes, not %d\n", size);
580     buffer = HeapAlloc(GetProcessHeap(), 0, size);
581     buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, ctx, buffer, unk, &IID_IUnknown);
582     HeapFree(GetProcessHeap(), 0, buffer);
583
584     /* Now for a non-NULL pointer. The marshalled data are two size DWORDS and then
585        the result of CoMarshalInterface called with the LOWORD of the ctx */
586
587     unk = &Test_Unknown;
588
589     CreateStreamOnHGlobal(h, TRUE, &stm);
590     CoMarshalInterface(stm, &IID_IUnknown, unk, LOWORD(ctx), NULL, MSHLFLAGS_NORMAL);
591     zero.QuadPart = 0;
592     IStream_Seek(stm, zero, STREAM_SEEK_CUR, &pos);
593     marshal_size = pos.u.LowPart;
594     marshal_data = GlobalLock(h);
595     trace("marshal_size %x\n", marshal_size);
596
597     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, umcb_ctx);
598     size = WdtpInterfacePointer_UserSize(&umcb.Flags, ctx, 0, unk, &IID_IUnknown);
599     ok(size >= marshal_size + 2 * sizeof(DWORD), "marshal size %x got %x\n", marshal_size, size);
600     trace("WdtpInterfacePointer_UserSize returned %x\n", size);
601     buffer = HeapAlloc(GetProcessHeap(), 0, size);
602     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, umcb_ctx);
603     buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, ctx, buffer, unk, &IID_IUnknown);
604     wireip = buffer;
605
606     ok(buffer_end == buffer + marshal_size + 2 * sizeof(DWORD), "buffer_end %p buffer %p\n", buffer_end, buffer);
607
608     ok(*(DWORD *)wireip == marshal_size, "wireip + 0x0 should be %x instead of %x\n", marshal_size, *(DWORD *)wireip);
609     wireip += sizeof(DWORD);
610     ok(*(DWORD *)wireip == marshal_size, "wireip + 0x4 should be %x instead of %x\n", marshal_size, *(DWORD *)wireip);
611     wireip += sizeof(DWORD);
612
613     ok(!memcmp(marshal_data, wireip, marshal_size), "buffer mismatch\n");
614     GlobalUnlock(h);
615     zero.QuadPart = 0;
616     IStream_Seek(stm, zero, STREAM_SEEK_SET, NULL);
617     CoReleaseMarshalData(stm);
618     IStream_Release(stm);
619
620     unk2 = NULL;
621     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, umcb_ctx);
622     WdtpInterfacePointer_UserUnmarshal(&umcb.Flags, buffer, &unk2, &IID_IUnknown);
623     ok(unk2 != NULL, "IUnknown object didn't unmarshal properly\n");
624     HeapFree(GetProcessHeap(), 0, buffer);
625     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
626     IUnknown_Release(unk2);
627 }
628
629 static void test_marshal_WdtpInterfacePointer(void)
630 {
631     /*
632      * There are two places where we can pass the marshalling ctx: as
633      * part of the umcb and as a separate flag.  The loword of that
634      * separate flag field is what matters.
635      */
636
637     /* All three are marshalled as inproc */
638     marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_INPROC);
639     marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_INPROC);
640     marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_INPROC, 0xffff));
641
642     /* All three are marshalled as remote */
643     marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE);
644     marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_DIFFERENTMACHINE);
645     marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_DIFFERENTMACHINE, 0xffff));
646 }
647
648 static void test_marshal_STGMEDIUM(void)
649 {
650     USER_MARSHAL_CB umcb;
651     MIDL_STUB_MESSAGE stub_msg;
652     RPC_MESSAGE rpc_msg;
653     unsigned char *buffer, *buffer_end, *expect_buffer, *expect_buffer_end;
654     ULONG size, expect_size;
655     STGMEDIUM med, med2;
656     IUnknown *unk = &Test_Unknown;
657     IStream *stm = &Test_Stream;
658
659     /* TYMED_NULL with pUnkForRelease */
660
661     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
662     expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 2 * sizeof(DWORD), unk, &IID_IUnknown);
663     expect_buffer = HeapAlloc(GetProcessHeap(), 0, expect_size);
664     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE);
665     expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer + 2 * sizeof(DWORD), unk, &IID_IUnknown);
666
667     med.tymed = TYMED_NULL;
668     U(med).pstg = NULL;
669     med.pUnkForRelease = unk;
670
671     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
672     size = STGMEDIUM_UserSize(&umcb.Flags, 0, &med);
673     ok(size == expect_size, "size %d should be %d bytes\n", size, expect_size);
674
675     buffer = HeapAlloc(GetProcessHeap(), 0, size);
676     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
677     buffer_end = STGMEDIUM_UserMarshal(&umcb.Flags, buffer, &med);
678     ok(buffer_end - buffer == expect_buffer_end - expect_buffer, "buffer size mismatch\n");
679     ok(*(DWORD*)buffer == TYMED_NULL, "got %08x\n", *(DWORD*)buffer);
680     ok(*((DWORD*)buffer+1) != 0, "got %08x\n", *((DWORD*)buffer+1));
681     ok(!memcmp(buffer+8, expect_buffer + 8, expect_buffer_end - expect_buffer - 8), "buffer mismatch\n");
682
683     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
684
685     /* native crashes if this is uninitialised, presumably because it
686        tries to release it */
687     med2.tymed = TYMED_NULL;
688     U(med2).pstm = NULL;
689     med2.pUnkForRelease = NULL;
690
691     STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2);
692
693     ok(med2.tymed == TYMED_NULL, "got tymed %x\n", med2.tymed);
694     ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n");
695
696     HeapFree(GetProcessHeap(), 0, buffer);
697     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
698     STGMEDIUM_UserFree(&umcb.Flags, &med2);
699
700     HeapFree(GetProcessHeap(), 0, expect_buffer);
701
702     /* TYMED_ISTREAM with pUnkForRelease */
703
704     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
705     expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 3 * sizeof(DWORD), (IUnknown*)stm, &IID_IStream);
706     expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, expect_size, unk, &IID_IUnknown);
707
708     expect_buffer = HeapAlloc(GetProcessHeap(), 0, expect_size);
709     /* There may be a hole between the two interfaces so init the buffer to something */
710     memset(expect_buffer, 0xcc, expect_size);
711     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE);
712     expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer + 3 * sizeof(DWORD), (IUnknown*)stm, &IID_IStream);
713     expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer_end, unk, &IID_IUnknown);
714
715     med.tymed = TYMED_ISTREAM;
716     U(med).pstm = stm;
717     med.pUnkForRelease = unk;
718
719     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
720     size = STGMEDIUM_UserSize(&umcb.Flags, 0, &med);
721     ok(size == expect_size, "size %d should be %d bytes\n", size, expect_size);
722
723     buffer = HeapAlloc(GetProcessHeap(), 0, size);
724     memset(buffer, 0xcc, size);
725     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
726     buffer_end = STGMEDIUM_UserMarshal(&umcb.Flags, buffer, &med);
727     ok(buffer_end - buffer == expect_buffer_end - expect_buffer, "buffer size mismatch\n");
728     ok(*(DWORD*)buffer == TYMED_ISTREAM, "got %08x\n", *(DWORD*)buffer);
729     ok(*((DWORD*)buffer+1) != 0, "got %08x\n", *((DWORD*)buffer+1));
730     ok(*((DWORD*)buffer+2) != 0, "got %08x\n", *((DWORD*)buffer+2));
731     ok(!memcmp(buffer + 12, expect_buffer + 12, (buffer_end - buffer) - 12), "buffer mismatch\n");
732
733     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
734
735     /* native crashes if this is uninitialised, presumably because it
736        tries to release it */
737     med2.tymed = TYMED_NULL;
738     U(med2).pstm = NULL;
739     med2.pUnkForRelease = NULL;
740
741     STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2);
742
743     ok(med2.tymed == TYMED_ISTREAM, "got tymed %x\n", med2.tymed);
744     ok(U(med2).pstm != NULL, "Incorrectly unmarshalled\n");
745     ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n");
746
747     HeapFree(GetProcessHeap(), 0, buffer);
748     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
749     STGMEDIUM_UserFree(&umcb.Flags, &med2);
750
751     HeapFree(GetProcessHeap(), 0, expect_buffer);
752 }
753
754 START_TEST(usrmarshal)
755 {
756     CoInitialize(NULL);
757
758     test_marshal_CLIPFORMAT();
759     test_marshal_HWND();
760     test_marshal_HGLOBAL();
761     test_marshal_HENHMETAFILE();
762     test_marshal_HMETAFILE();
763     test_marshal_HMETAFILEPICT();
764     test_marshal_WdtpInterfacePointer();
765     test_marshal_STGMEDIUM();
766
767     CoUninitialize();
768 }