[OLE32_WINETEST]
[reactos.git] / rostests / winetests / ole32 / 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 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
192 for(block_size = 0; block_size <= 17; block_size++)
193 {
194 ULONG actual_size, expected_size;
195
196 hglobal = GlobalAlloc(0, block_size);
197 buffer = GlobalLock(hglobal);
198 for (i = 0; i < block_size; i++)
199 buffer[i] = i;
200 GlobalUnlock(hglobal);
201 actual_size = GlobalSize(hglobal);
202 expected_size = actual_size + 5 * sizeof(DWORD);
203 trace("%d: actual size %d\n", block_size, actual_size);
204 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
205 size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal);
206 /* native is poorly programmed and allocates 4/8 bytes more than it needs to
207 * here - Wine doesn't have to emulate that */
208 ok(size == expected_size ||
209 broken(size == expected_size + 4) ||
210 broken(size == expected_size + 8),
211 "%d: got size %d\n", block_size, size);
212 buffer = HeapAlloc(GetProcessHeap(), 0, size);
213 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
214 HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal);
215 wirehglobal = buffer;
216 ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal);
217 wirehglobal += sizeof(ULONG);
218 ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0x4 should be HGLOBAL\n");
219 wirehglobal += sizeof(ULONG);
220 ok(*(ULONG *)wirehglobal == actual_size, "%d: buffer+0x8 %08x\n", block_size, *(ULONG *)wirehglobal);
221 wirehglobal += sizeof(ULONG);
222 ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0xc should be HGLOBAL\n");
223 wirehglobal += sizeof(ULONG);
224 ok(*(ULONG *)wirehglobal == actual_size, "%d: buffer+0x10 %08x\n", block_size, *(ULONG *)wirehglobal);
225 wirehglobal += sizeof(ULONG);
226 for (i = 0; i < block_size; i++)
227 ok(wirehglobal[i] == i, "buffer+0x%x should be %d\n", 0x10 + i, i);
228
229 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
230 HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2);
231 ok(hglobal2 != NULL, "Didn't unmarshal properly\n");
232 HeapFree(GetProcessHeap(), 0, buffer);
233 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
234 HGLOBAL_UserFree(&umcb.Flags, &hglobal2);
235 GlobalFree(hglobal);
236 }
237 }
238
239 static HENHMETAFILE create_emf(void)
240 {
241 const RECT rect = {0, 0, 100, 100};
242 HDC hdc = CreateEnhMetaFile(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
243 ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
244 return CloseEnhMetaFile(hdc);
245 }
246
247 static void test_marshal_HENHMETAFILE(void)
248 {
249 USER_MARSHAL_CB umcb;
250 MIDL_STUB_MESSAGE stub_msg;
251 RPC_MESSAGE rpc_msg;
252 unsigned char *buffer;
253 ULONG size;
254 HENHMETAFILE hemf;
255 HENHMETAFILE hemf2 = NULL;
256 unsigned char *wirehemf;
257
258 hemf = create_emf();
259
260 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
261 size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf);
262 ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
263 buffer = HeapAlloc(GetProcessHeap(), 0, size);
264 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
265 HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf);
266 wirehemf = buffer;
267 ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
268 wirehemf += sizeof(DWORD);
269 ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
270 wirehemf += sizeof(DWORD);
271 ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf);
272 wirehemf += sizeof(DWORD);
273 ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehemf);
274 wirehemf += sizeof(DWORD);
275 ok(*(DWORD *)wirehemf == EMR_HEADER, "wirestgm + 0x10 should be EMR_HEADER instead of %d\n", *(DWORD *)wirehemf);
276 wirehemf += sizeof(DWORD);
277 /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits
278 * at this point */
279
280 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
281 HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2);
282 ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n");
283 HeapFree(GetProcessHeap(), 0, buffer);
284 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
285 HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
286 DeleteEnhMetaFile(hemf);
287
288 /* test NULL emf */
289 hemf = NULL;
290
291 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
292 size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf);
293 ok(size == 8, "size should be 8 bytes, not %d\n", size);
294 buffer = HeapAlloc(GetProcessHeap(), 0, size);
295 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
296 HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf);
297 wirehemf = buffer;
298 ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
299 wirehemf += sizeof(DWORD);
300 ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
301 wirehemf += sizeof(DWORD);
302
303 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
304 HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2);
305 ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n");
306 HeapFree(GetProcessHeap(), 0, buffer);
307 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
308 HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
309 }
310
311 static HMETAFILE create_mf(void)
312 {
313 RECT rect = {0, 0, 100, 100};
314 HDC hdc = CreateMetaFile(NULL);
315 ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
316 return CloseMetaFile(hdc);
317 }
318
319 static void test_marshal_HMETAFILE(void)
320 {
321 USER_MARSHAL_CB umcb;
322 MIDL_STUB_MESSAGE stub_msg;
323 RPC_MESSAGE rpc_msg;
324 unsigned char *buffer;
325 ULONG size;
326 HMETAFILE hmf;
327 HMETAFILE hmf2 = NULL;
328 unsigned char *wirehmf;
329
330 hmf = create_mf();
331
332 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
333 size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
334 ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
335 buffer = HeapAlloc(GetProcessHeap(), 0, size);
336 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
337 HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
338 wirehmf = buffer;
339 ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
340 wirehmf += sizeof(DWORD);
341 ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
342 wirehmf += sizeof(DWORD);
343 ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
344 wirehmf += sizeof(DWORD);
345 ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
346 wirehmf += sizeof(DWORD);
347 ok(*(WORD *)wirehmf == 1, "wirestgm + 0x10 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmf);
348 wirehmf += sizeof(DWORD);
349 /* ... rest of data not tested - refer to tests for GetMetaFileBits
350 * at this point */
351
352 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
353 HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
354 ok(hmf2 != NULL, "HMETAFILE didn't unmarshal\n");
355 HeapFree(GetProcessHeap(), 0, buffer);
356 HMETAFILE_UserFree(&umcb.Flags, &hmf2);
357 DeleteMetaFile(hmf);
358
359 /* test NULL emf */
360 hmf = NULL;
361
362 size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
363 ok(size == 8, "size should be 8 bytes, not %d\n", size);
364 buffer = HeapAlloc(GetProcessHeap(), 0, size);
365 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
366 HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
367 wirehmf = buffer;
368 ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
369 wirehmf += sizeof(DWORD);
370 ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
371 wirehmf += sizeof(DWORD);
372
373 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
374 HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
375 ok(hmf2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
376 HeapFree(GetProcessHeap(), 0, buffer);
377 HMETAFILE_UserFree(&umcb.Flags, &hmf2);
378 }
379
380 #define USER_MARSHAL_PTR_PREFIX \
381 ( (DWORD)'U' | ( (DWORD)'s' << 8 ) | \
382 ( (DWORD)'e' << 16 ) | ( (DWORD)'r' << 24 ) )
383
384 static void test_marshal_HMETAFILEPICT(void)
385 {
386 USER_MARSHAL_CB umcb;
387 MIDL_STUB_MESSAGE stub_msg;
388 RPC_MESSAGE rpc_msg;
389 unsigned char *buffer, *buffer_end;
390 ULONG size;
391 HMETAFILEPICT hmfp;
392 HMETAFILEPICT hmfp2 = NULL;
393 METAFILEPICT *pmfp;
394 unsigned char *wirehmfp;
395
396 hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(*pmfp));
397 pmfp = GlobalLock(hmfp);
398 pmfp->mm = MM_ISOTROPIC;
399 pmfp->xExt = 1;
400 pmfp->yExt = 2;
401 pmfp->hMF = create_mf();
402 GlobalUnlock(hmfp);
403
404 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
405 size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp);
406 ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
407 trace("size is %d\n", size);
408 buffer = HeapAlloc(GetProcessHeap(), 0, size);
409 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
410 buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp);
411 wirehmfp = buffer;
412 ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
413 wirehmfp += sizeof(DWORD);
414 ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
415 wirehmfp += sizeof(DWORD);
416 ok(*(DWORD *)wirehmfp == MM_ISOTROPIC, "wirestgm + 0x8 should be MM_ISOTROPIC instead of 0x%08x\n", *(DWORD *)wirehmfp);
417 wirehmfp += sizeof(DWORD);
418 ok(*(DWORD *)wirehmfp == 1, "wirestgm + 0xc should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
419 wirehmfp += sizeof(DWORD);
420 ok(*(DWORD *)wirehmfp == 2, "wirestgm + 0x10 should be 2 instead of 0x%08x\n", *(DWORD *)wirehmfp);
421 wirehmfp += sizeof(DWORD);
422 ok(*(DWORD *)wirehmfp == USER_MARSHAL_PTR_PREFIX, "wirestgm + 0x14 should be \"User\" instead of 0x%08x\n", *(DWORD *)wirehmfp);
423 wirehmfp += sizeof(DWORD);
424 ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x18 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
425 wirehmfp += sizeof(DWORD);
426 pmfp = GlobalLock(hmfp);
427 ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)pmfp->hMF, "wirestgm + 0x1c should be pmfp->hMF instead of 0x%08x\n", *(DWORD *)wirehmfp);
428 GlobalUnlock(hmfp);
429 wirehmfp += sizeof(DWORD);
430 /* Note use (buffer_end - buffer) instead of size here, because size is an
431 * overestimate with native */
432 ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x20 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
433 wirehmfp += sizeof(DWORD);
434 ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x28), "wirestgm + 0x24 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
435 wirehmfp += sizeof(DWORD);
436 ok(*(WORD *)wirehmfp == 1, "wirehmfp + 0x28 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
437 wirehmfp += sizeof(DWORD);
438 /* ... rest of data not tested - refer to tests for GetMetaFileBits
439 * at this point */
440
441 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
442 HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2);
443 ok(hmfp2 != NULL, "HMETAFILEPICT didn't unmarshal\n");
444 HeapFree(GetProcessHeap(), 0, buffer);
445 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
446 HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
447 pmfp = GlobalLock(hmfp);
448 DeleteMetaFile(pmfp->hMF);
449 GlobalUnlock(hmfp);
450 GlobalFree(hmfp);
451
452 /* test NULL emf */
453 hmfp = NULL;
454
455 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
456 size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp);
457 ok(size == 8, "size should be 8 bytes, not %d\n", size);
458 buffer = HeapAlloc(GetProcessHeap(), 0, size);
459 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
460 HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp);
461 wirehmfp = buffer;
462 ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
463 wirehmfp += sizeof(DWORD);
464 ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
465 wirehmfp += sizeof(DWORD);
466
467 hmfp2 = NULL;
468 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
469 HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2);
470 ok(hmfp2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
471 HeapFree(GetProcessHeap(), 0, buffer);
472 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
473 HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
474 }
475
476 static HRESULT WINAPI Test_IUnknown_QueryInterface(
477 LPUNKNOWN iface,
478 REFIID riid,
479 LPVOID *ppvObj)
480 {
481 if (ppvObj == NULL) return E_POINTER;
482
483 if (IsEqualGUID(riid, &IID_IUnknown))
484 {
485 *ppvObj = iface;
486 IUnknown_AddRef(iface);
487 return S_OK;
488 }
489
490 *ppvObj = NULL;
491 return E_NOINTERFACE;
492 }
493
494 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
495 {
496 return 2; /* non-heap-based object */
497 }
498
499 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
500 {
501 return 1; /* non-heap-based object */
502 }
503
504 static const IUnknownVtbl TestUnknown_Vtbl =
505 {
506 Test_IUnknown_QueryInterface,
507 Test_IUnknown_AddRef,
508 Test_IUnknown_Release,
509 };
510
511 static HRESULT WINAPI Test_IStream_QueryInterface(IStream *iface,
512 REFIID riid, LPVOID *ppvObj)
513 {
514 if (ppvObj == NULL) return E_POINTER;
515
516 if (IsEqualIID(riid, &IID_IUnknown) ||
517 IsEqualIID(riid, &IID_IStream))
518 {
519 *ppvObj = iface;
520 IStream_AddRef(iface);
521 return S_OK;
522 }
523
524 *ppvObj = NULL;
525 return E_NOINTERFACE;
526 }
527
528 static ULONG WINAPI Test_IStream_AddRef(IStream *iface)
529 {
530 return 2; /* non-heap-based object */
531 }
532
533 static ULONG WINAPI Test_IStream_Release(IStream *iface)
534 {
535 return 1; /* non-heap-based object */
536 }
537
538 static const IStreamVtbl TestStream_Vtbl =
539 {
540 Test_IStream_QueryInterface,
541 Test_IStream_AddRef,
542 Test_IStream_Release
543 /* the rest can be NULLs */
544 };
545
546 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
547 static IStream Test_Stream = { &TestStream_Vtbl };
548
549 ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG *, ULONG, ULONG, IUnknown *, REFIID);
550 unsigned char * __RPC_USER WdtpInterfacePointer_UserMarshal(ULONG *, ULONG, unsigned char *, IUnknown *, REFIID);
551 unsigned char * __RPC_USER WdtpInterfacePointer_UserUnmarshal(ULONG *, unsigned char *, IUnknown **, REFIID);
552 void __RPC_USER WdtpInterfacePointer_UserFree(IUnknown *);
553
554 static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx)
555 {
556 USER_MARSHAL_CB umcb;
557 MIDL_STUB_MESSAGE stub_msg;
558 RPC_MESSAGE rpc_msg;
559 unsigned char *buffer, *buffer_end;
560 ULONG size;
561 IUnknown *unk;
562 IUnknown *unk2;
563 unsigned char *wireip;
564 HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, 0);
565 IStream *stm;
566 void *marshal_data;
567 LARGE_INTEGER zero;
568 ULARGE_INTEGER pos;
569 DWORD marshal_size;
570
571 /* shows that the WdtpInterfacePointer functions don't marshal anything for
572 * NULL pointers, so code using these functions must handle that case
573 * itself */
574
575 unk = NULL;
576 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, umcb_ctx);
577 size = WdtpInterfacePointer_UserSize(&umcb.Flags, ctx, 0, unk, &IID_IUnknown);
578 ok(size == 0, "size should be 0 bytes, not %d\n", size);
579 buffer = HeapAlloc(GetProcessHeap(), 0, size);
580 buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, ctx, buffer, unk, &IID_IUnknown);
581 wireip = buffer;
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 (diff %x)\n", buffer_end, buffer, 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 WdtpInterfacePointer_UserFree(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 }