3919395800f0536035b84bc491d4dedbc1ef7298
[reactos.git] / modules / 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 ULONG __RPC_USER HBRUSH_UserSize(ULONG *, ULONG, HBRUSH *);
48 unsigned char * __RPC_USER HBRUSH_UserMarshal(ULONG *, unsigned char *, HBRUSH *);
49 unsigned char * __RPC_USER HBRUSH_UserUnmarshal(ULONG *, unsigned char *, HBRUSH *);
50 void __RPC_USER HBRUSH_UserFree(ULONG *, HBRUSH *);
51
52 static BOOL g_expect_user_alloc;
53 static void * WINAPI user_allocate(SIZE_T size)
54 {
55 ok(g_expect_user_alloc, "unexpected user_allocate call\n");
56 return CoTaskMemAlloc(size);
57 }
58
59 static BOOL g_expect_user_free;
60 static void WINAPI user_free(void *p)
61 {
62 ok(g_expect_user_free, "unexpected user_free call\n");
63 CoTaskMemFree(p);
64 }
65
66 static void init_user_marshal_cb(USER_MARSHAL_CB *umcb,
67 PMIDL_STUB_MESSAGE stub_msg,
68 PRPC_MESSAGE rpc_msg, unsigned char *buffer,
69 unsigned int size, MSHCTX context)
70 {
71 memset(rpc_msg, 0, sizeof(*rpc_msg));
72 rpc_msg->Buffer = buffer;
73 rpc_msg->BufferLength = size;
74
75 memset(stub_msg, 0, sizeof(*stub_msg));
76 stub_msg->RpcMsg = rpc_msg;
77 stub_msg->Buffer = buffer;
78 stub_msg->pfnAllocate = user_allocate;
79 stub_msg->pfnFree = user_free;
80
81 memset(umcb, 0, sizeof(*umcb));
82 umcb->Flags = MAKELONG(context, NDR_LOCAL_DATA_REPRESENTATION);
83 umcb->pStubMsg = stub_msg;
84 umcb->Signature = USER_MARSHAL_CB_SIGNATURE;
85 umcb->CBType = buffer ? USER_MARSHAL_CB_UNMARSHALL : USER_MARSHAL_CB_BUFFER_SIZE;
86 }
87
88 #define RELEASEMARSHALDATA WM_USER
89
90 struct host_object_data
91 {
92 IStream *stream;
93 IID iid;
94 IUnknown *object;
95 MSHLFLAGS marshal_flags;
96 HANDLE marshal_event;
97 IMessageFilter *filter;
98 };
99
100 static DWORD CALLBACK host_object_proc(LPVOID p)
101 {
102 struct host_object_data *data = p;
103 HRESULT hr;
104 MSG msg;
105
106 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
107
108 if (data->filter)
109 {
110 IMessageFilter * prev_filter = NULL;
111 hr = CoRegisterMessageFilter(data->filter, &prev_filter);
112 if (prev_filter) IMessageFilter_Release(prev_filter);
113 ok(hr == S_OK, "got %08x\n", hr);
114 }
115
116 hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
117 ok(hr == S_OK, "got %08x\n", hr);
118
119 /* force the message queue to be created before signaling parent thread */
120 PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
121
122 SetEvent(data->marshal_event);
123
124 while (GetMessageA(&msg, NULL, 0, 0))
125 {
126 if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
127 {
128 CoReleaseMarshalData(data->stream);
129 SetEvent((HANDLE)msg.lParam);
130 }
131 else
132 DispatchMessageA(&msg);
133 }
134
135 HeapFree(GetProcessHeap(), 0, data);
136
137 CoUninitialize();
138
139 return hr;
140 }
141
142 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
143 {
144 DWORD tid = 0;
145 HANDLE marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
146 struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
147
148 data->stream = stream;
149 data->iid = *riid;
150 data->object = object;
151 data->marshal_flags = marshal_flags;
152 data->marshal_event = marshal_event;
153 data->filter = filter;
154
155 *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
156
157 /* wait for marshaling to complete before returning */
158 ok( !WaitForSingleObject(marshal_event, 10000), "wait timed out\n" );
159 CloseHandle(marshal_event);
160
161 return tid;
162 }
163
164 static void end_host_object(DWORD tid, HANDLE thread)
165 {
166 BOOL ret = PostThreadMessageA(tid, WM_QUIT, 0, 0);
167 ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
168 /* be careful of races - don't return until hosting thread has terminated */
169 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
170 CloseHandle(thread);
171 }
172
173 static const char cf_marshaled[] =
174 {
175 0x9, 0x0, 0x0, 0x0,
176 0x0, 0x0, 0x0, 0x0,
177 0x9, 0x0, 0x0, 0x0,
178 'M', 0x0, 'y', 0x0,
179 'F', 0x0, 'o', 0x0,
180 'r', 0x0, 'm', 0x0,
181 'a', 0x0, 't', 0x0,
182 0x0, 0x0
183 };
184
185 static void test_marshal_CLIPFORMAT(void)
186 {
187 USER_MARSHAL_CB umcb;
188 MIDL_STUB_MESSAGE stub_msg;
189 RPC_MESSAGE rpc_msg;
190 unsigned char *buffer, *buffer_end;
191 ULONG i, size;
192 CLIPFORMAT cf = RegisterClipboardFormatA("MyFormat");
193 CLIPFORMAT cf2;
194
195 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
196 size = CLIPFORMAT_UserSize(&umcb.Flags, 1, &cf);
197 ok(size == 12 + sizeof(cf_marshaled) ||
198 broken(size == 16 + sizeof(cf_marshaled)), /* win64 adds 4 extra (unused) bytes */
199 "CLIPFORMAT: Wrong size %d\n", size);
200
201 buffer = HeapAlloc(GetProcessHeap(), 0, size);
202 memset( buffer, 0xcc, size );
203 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
204 buffer_end = CLIPFORMAT_UserMarshal(&umcb.Flags, buffer + 1, &cf);
205 ok(buffer_end == buffer + 12 + sizeof(cf_marshaled), "got %p buffer %p\n", buffer_end, buffer);
206 ok(*(LONG *)(buffer + 4) == WDT_REMOTE_CALL, "CLIPFORMAT: Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(LONG *)(buffer + 0));
207 ok(*(DWORD *)(buffer + 8) == cf, "CLIPFORMAT: Marshaled value should be 0x%04x instead of 0x%04x\n", cf, *(DWORD *)(buffer + 4));
208 ok(!memcmp(buffer + 12, cf_marshaled, min( sizeof(cf_marshaled), size-12 )), "Marshaled data differs\n");
209 if (size > sizeof(cf_marshaled) + 12) /* make sure the extra bytes are not used */
210 for (i = sizeof(cf_marshaled) + 12; i < size; i++)
211 ok( buffer[i] == 0xcc, "buffer offset %u has been set to %x\n", i, buffer[i] );
212
213 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
214 buffer_end = CLIPFORMAT_UserUnmarshal(&umcb.Flags, buffer + 1, &cf2);
215 ok(buffer_end == buffer + 12 + sizeof(cf_marshaled), "got %p buffer %p\n", buffer_end, buffer);
216 ok(cf == cf2, "CLIPFORMAT: Didn't unmarshal properly\n");
217 HeapFree(GetProcessHeap(), 0, buffer);
218
219 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
220 CLIPFORMAT_UserFree(&umcb.Flags, &cf2);
221 }
222
223 static void test_marshal_HWND(void)
224 {
225 USER_MARSHAL_CB umcb;
226 MIDL_STUB_MESSAGE stub_msg;
227 RPC_MESSAGE rpc_msg;
228 unsigned char *buffer, *buffer_end;
229 ULONG size;
230 HWND hwnd = GetDesktopWindow();
231 HWND hwnd2;
232 wireHWND wirehwnd;
233
234 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
235 size = HWND_UserSize(&umcb.Flags, 1, &hwnd);
236 ok(size == 4 + sizeof(*wirehwnd), "Wrong size %d\n", size);
237
238 buffer = HeapAlloc(GetProcessHeap(), 0, size);
239 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
240 buffer_end = HWND_UserMarshal(&umcb.Flags, buffer + 1, &hwnd);
241 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
242 wirehwnd = (wireHWND)(buffer + 4);
243 ok(wirehwnd->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehwnd->fContext);
244 ok(wirehwnd->u.hInproc == (LONG_PTR)hwnd, "Marshaled value should be %p instead of %x\n", hwnd, wirehwnd->u.hRemote);
245
246 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
247 buffer_end = HWND_UserUnmarshal(&umcb.Flags, buffer + 1, &hwnd2);
248 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
249 ok(hwnd == hwnd2, "Didn't unmarshal properly\n");
250 HeapFree(GetProcessHeap(), 0, buffer);
251
252 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
253 HWND_UserFree(&umcb.Flags, &hwnd2);
254 }
255
256 static void test_marshal_HGLOBAL(void)
257 {
258 USER_MARSHAL_CB umcb;
259 MIDL_STUB_MESSAGE stub_msg;
260 RPC_MESSAGE rpc_msg;
261 unsigned char *buffer;
262 ULONG size, block_size;
263 HGLOBAL hglobal;
264 HGLOBAL hglobal2;
265 unsigned char *wirehglobal;
266 int i;
267
268 hglobal = NULL;
269 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
270 size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal);
271 /* native is poorly programmed and allocates 4/8 bytes more than it needs to
272 * here - Wine doesn't have to emulate that */
273 ok((size == 8) || broken(size == 12) || broken(size == 16), "Size should be 8, instead of %d\n", size);
274 buffer = HeapAlloc(GetProcessHeap(), 0, size);
275 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
276 HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal);
277 wirehglobal = buffer;
278 ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal);
279 wirehglobal += sizeof(ULONG);
280 ok(*(ULONG *)wirehglobal == 0, "buffer+4 should be HGLOBAL\n");
281 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
282 hglobal2 = NULL;
283 HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2);
284 ok(hglobal2 == hglobal, "Didn't unmarshal properly\n");
285 HeapFree(GetProcessHeap(), 0, buffer);
286 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
287 HGLOBAL_UserFree(&umcb.Flags, &hglobal2);
288
289
290 for(block_size = 0; block_size <= 17; block_size++)
291 {
292 ULONG actual_size, expected_size;
293
294 hglobal = GlobalAlloc(0, block_size);
295 buffer = GlobalLock(hglobal);
296 for (i = 0; i < block_size; i++)
297 buffer[i] = i;
298 GlobalUnlock(hglobal);
299 actual_size = GlobalSize(hglobal);
300 expected_size = actual_size + 5 * sizeof(DWORD);
301 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
302 size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal);
303 /* native is poorly programmed and allocates 4/8 bytes more than it needs to
304 * here - Wine doesn't have to emulate that */
305 ok(size == expected_size ||
306 broken(size == expected_size + 4) ||
307 broken(size == expected_size + 8),
308 "%d: got size %d\n", block_size, size);
309 buffer = HeapAlloc(GetProcessHeap(), 0, size);
310 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
311 HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal);
312 wirehglobal = buffer;
313 ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal);
314 wirehglobal += sizeof(ULONG);
315 ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0x4 should be HGLOBAL\n");
316 wirehglobal += sizeof(ULONG);
317 ok(*(ULONG *)wirehglobal == actual_size, "%d: buffer+0x8 %08x\n", block_size, *(ULONG *)wirehglobal);
318 wirehglobal += sizeof(ULONG);
319 ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0xc should be HGLOBAL\n");
320 wirehglobal += sizeof(ULONG);
321 ok(*(ULONG *)wirehglobal == actual_size, "%d: buffer+0x10 %08x\n", block_size, *(ULONG *)wirehglobal);
322 wirehglobal += sizeof(ULONG);
323 for (i = 0; i < block_size; i++)
324 ok(wirehglobal[i] == i, "buffer+0x%x should be %d\n", 0x10 + i, i);
325
326 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
327 hglobal2 = NULL;
328 HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2);
329 ok(hglobal2 != NULL, "Didn't unmarshal properly\n");
330 HeapFree(GetProcessHeap(), 0, buffer);
331 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
332 HGLOBAL_UserFree(&umcb.Flags, &hglobal2);
333 GlobalFree(hglobal);
334 }
335 }
336
337 static HENHMETAFILE create_emf(void)
338 {
339 const RECT rect = {0, 0, 100, 100};
340 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
341 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
342 return CloseEnhMetaFile(hdc);
343 }
344
345 static void test_marshal_HENHMETAFILE(void)
346 {
347 USER_MARSHAL_CB umcb;
348 MIDL_STUB_MESSAGE stub_msg;
349 RPC_MESSAGE rpc_msg;
350 unsigned char *buffer, *buffer_end;
351 ULONG size;
352 HENHMETAFILE hemf;
353 HENHMETAFILE hemf2 = NULL;
354 unsigned char *wirehemf;
355
356 hemf = create_emf();
357
358 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
359 size = HENHMETAFILE_UserSize(&umcb.Flags, 1, &hemf);
360 ok(size > 24, "size should be at least 24 bytes, not %d\n", size);
361 buffer = HeapAlloc(GetProcessHeap(), 0, size);
362 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
363 buffer_end = HENHMETAFILE_UserMarshal(&umcb.Flags, buffer + 1, &hemf);
364 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
365 wirehemf = buffer + 4;
366 ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
367 wirehemf += sizeof(DWORD);
368 ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
369 wirehemf += sizeof(DWORD);
370 ok(*(DWORD *)wirehemf == (size - 0x14), "wirestgm + 0x8 should be size - 0x14 instead of 0x%08x\n", *(DWORD *)wirehemf);
371 wirehemf += sizeof(DWORD);
372 ok(*(DWORD *)wirehemf == (size - 0x14), "wirestgm + 0xc should be size - 0x14 instead of 0x%08x\n", *(DWORD *)wirehemf);
373 wirehemf += sizeof(DWORD);
374 ok(*(DWORD *)wirehemf == EMR_HEADER, "wirestgm + 0x10 should be EMR_HEADER instead of %d\n", *(DWORD *)wirehemf);
375 /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits
376 * at this point */
377
378 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
379 buffer_end = HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer + 1, &hemf2);
380 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
381 ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n");
382 HeapFree(GetProcessHeap(), 0, buffer);
383 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
384 HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
385 DeleteEnhMetaFile(hemf);
386
387 /* test NULL emf */
388 hemf = NULL;
389
390 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
391 size = HENHMETAFILE_UserSize(&umcb.Flags, 1, &hemf);
392 ok(size == 12, "size should be 12 bytes, not %d\n", size);
393 buffer = HeapAlloc(GetProcessHeap(), 0, size);
394 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
395 buffer_end = HENHMETAFILE_UserMarshal(&umcb.Flags, buffer + 1, &hemf);
396 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
397 wirehemf = buffer + 4;
398 ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf);
399 wirehemf += sizeof(DWORD);
400 ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf);
401
402 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
403 buffer_end = HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer + 1, &hemf2);
404 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
405 ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n");
406 HeapFree(GetProcessHeap(), 0, buffer);
407 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
408 HENHMETAFILE_UserFree(&umcb.Flags, &hemf2);
409 }
410
411 static HMETAFILE create_mf(void)
412 {
413 RECT rect = {0, 0, 100, 100};
414 HDC hdc = CreateMetaFileA(NULL);
415 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
416 return CloseMetaFile(hdc);
417 }
418
419 static void test_marshal_HMETAFILE(void)
420 {
421 USER_MARSHAL_CB umcb;
422 MIDL_STUB_MESSAGE stub_msg;
423 RPC_MESSAGE rpc_msg;
424 unsigned char *buffer;
425 ULONG size;
426 HMETAFILE hmf;
427 HMETAFILE hmf2 = NULL;
428 unsigned char *wirehmf;
429
430 hmf = create_mf();
431
432 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
433 size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
434 ok(size > 20, "size should be at least 20 bytes, not %d\n", size);
435 buffer = HeapAlloc(GetProcessHeap(), 0, size);
436 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
437 HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
438 wirehmf = buffer;
439 ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
440 wirehmf += sizeof(DWORD);
441 ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
442 wirehmf += sizeof(DWORD);
443 ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
444 wirehmf += sizeof(DWORD);
445 ok(*(DWORD *)wirehmf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08x\n", *(DWORD *)wirehmf);
446 wirehmf += sizeof(DWORD);
447 ok(*(WORD *)wirehmf == 1, "wirestgm + 0x10 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmf);
448 wirehmf += sizeof(DWORD);
449 /* ... rest of data not tested - refer to tests for GetMetaFileBits
450 * at this point */
451
452 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
453 HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
454 ok(hmf2 != NULL, "HMETAFILE didn't unmarshal\n");
455 HeapFree(GetProcessHeap(), 0, buffer);
456 HMETAFILE_UserFree(&umcb.Flags, &hmf2);
457 DeleteMetaFile(hmf);
458
459 /* test NULL emf */
460 hmf = NULL;
461
462 size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf);
463 ok(size == 8, "size should be 8 bytes, not %d\n", size);
464 buffer = HeapAlloc(GetProcessHeap(), 0, size);
465 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
466 HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf);
467 wirehmf = buffer;
468 ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf);
469 wirehmf += sizeof(DWORD);
470 ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf);
471 wirehmf += sizeof(DWORD);
472
473 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
474 HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2);
475 ok(hmf2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
476 HeapFree(GetProcessHeap(), 0, buffer);
477 HMETAFILE_UserFree(&umcb.Flags, &hmf2);
478 }
479
480 #define USER_MARSHAL_PTR_PREFIX \
481 ( (DWORD)'U' | ( (DWORD)'s' << 8 ) | \
482 ( (DWORD)'e' << 16 ) | ( (DWORD)'r' << 24 ) )
483
484 static void test_marshal_HMETAFILEPICT(void)
485 {
486 USER_MARSHAL_CB umcb;
487 MIDL_STUB_MESSAGE stub_msg;
488 RPC_MESSAGE rpc_msg;
489 unsigned char *buffer, *buffer_end;
490 ULONG size;
491 HMETAFILEPICT hmfp;
492 HMETAFILEPICT hmfp2 = NULL;
493 METAFILEPICT *pmfp;
494 unsigned char *wirehmfp;
495
496 hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(*pmfp));
497 pmfp = GlobalLock(hmfp);
498 pmfp->mm = MM_ISOTROPIC;
499 pmfp->xExt = 1;
500 pmfp->yExt = 2;
501 pmfp->hMF = create_mf();
502 GlobalUnlock(hmfp);
503
504 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
505 size = HMETAFILEPICT_UserSize(&umcb.Flags, 1, &hmfp);
506 ok(size > 24, "size should be at least 24 bytes, not %d\n", size);
507 buffer = HeapAlloc(GetProcessHeap(), 0, size);
508 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
509 buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer + 1, &hmfp);
510 wirehmfp = buffer + 4;
511 ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
512 wirehmfp += sizeof(DWORD);
513 ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
514 wirehmfp += sizeof(DWORD);
515 ok(*(DWORD *)wirehmfp == MM_ISOTROPIC, "wirestgm + 0x8 should be MM_ISOTROPIC instead of 0x%08x\n", *(DWORD *)wirehmfp);
516 wirehmfp += sizeof(DWORD);
517 ok(*(DWORD *)wirehmfp == 1, "wirestgm + 0xc should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
518 wirehmfp += sizeof(DWORD);
519 ok(*(DWORD *)wirehmfp == 2, "wirestgm + 0x10 should be 2 instead of 0x%08x\n", *(DWORD *)wirehmfp);
520 wirehmfp += sizeof(DWORD);
521 ok(*(DWORD *)wirehmfp == USER_MARSHAL_PTR_PREFIX, "wirestgm + 0x14 should be \"User\" instead of 0x%08x\n", *(DWORD *)wirehmfp);
522 wirehmfp += sizeof(DWORD);
523 ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x18 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
524 wirehmfp += sizeof(DWORD);
525 pmfp = GlobalLock(hmfp);
526 ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)pmfp->hMF, "wirestgm + 0x1c should be pmfp->hMF instead of 0x%08x\n", *(DWORD *)wirehmfp);
527 GlobalUnlock(hmfp);
528 wirehmfp += sizeof(DWORD);
529 /* Note use (buffer_end - buffer) instead of size here, because size is an
530 * overestimate with native */
531 ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x2c), "wirestgm + 0x20 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
532 wirehmfp += sizeof(DWORD);
533 ok(*(DWORD *)wirehmfp == (buffer_end - buffer - 0x2c), "wirestgm + 0x24 should be size - 0x34 instead of 0x%08x\n", *(DWORD *)wirehmfp);
534 wirehmfp += sizeof(DWORD);
535 ok(*(WORD *)wirehmfp == 1, "wirehmfp + 0x28 should be 1 instead of 0x%08x\n", *(DWORD *)wirehmfp);
536 /* ... rest of data not tested - refer to tests for GetMetaFileBits
537 * at this point */
538
539 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
540 HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer + 1, &hmfp2);
541 ok(hmfp2 != NULL, "HMETAFILEPICT didn't unmarshal\n");
542 HeapFree(GetProcessHeap(), 0, buffer);
543 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
544 HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
545 pmfp = GlobalLock(hmfp);
546 DeleteMetaFile(pmfp->hMF);
547 GlobalUnlock(hmfp);
548 GlobalFree(hmfp);
549
550 /* test NULL emf */
551 hmfp = NULL;
552
553 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
554 size = HMETAFILEPICT_UserSize(&umcb.Flags, 1, &hmfp);
555 ok(size == 12, "size should be 12 bytes, not %d\n", size);
556 buffer = HeapAlloc(GetProcessHeap(), 0, size);
557 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
558 buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer + 1, &hmfp);
559 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
560 wirehmfp = buffer + 4;
561 ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp);
562 wirehmfp += sizeof(DWORD);
563 ok(*(DWORD *)wirehmfp == (DWORD)(DWORD_PTR)hmfp, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmfp);
564 wirehmfp += sizeof(DWORD);
565
566 hmfp2 = NULL;
567 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
568 buffer_end = HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer + 1, &hmfp2);
569 ok(buffer_end == buffer + size, "got %p buffer %p\n", buffer_end, buffer);
570 ok(hmfp2 == NULL, "NULL HMETAFILE didn't unmarshal\n");
571 HeapFree(GetProcessHeap(), 0, buffer);
572 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
573 HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
574 }
575
576 typedef struct
577 {
578 IUnknown IUnknown_iface;
579 LONG refs;
580 } TestUnknown;
581
582 static inline TestUnknown *impl_from_IUnknown(IUnknown *iface)
583 {
584 return CONTAINING_RECORD(iface, TestUnknown, IUnknown_iface);
585 }
586
587 static HRESULT WINAPI Test_IUnknown_QueryInterface(
588 LPUNKNOWN iface,
589 REFIID riid,
590 LPVOID *ppvObj)
591 {
592 if (ppvObj == NULL) return E_POINTER;
593
594 if (IsEqualGUID(riid, &IID_IUnknown))
595 {
596 *ppvObj = iface;
597 IUnknown_AddRef(iface);
598 return S_OK;
599 }
600
601 *ppvObj = NULL;
602 return E_NOINTERFACE;
603 }
604
605 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
606 {
607 TestUnknown *This = impl_from_IUnknown(iface);
608 return InterlockedIncrement(&This->refs);
609 }
610
611 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
612 {
613 TestUnknown *This = impl_from_IUnknown(iface);
614 return InterlockedDecrement(&This->refs);
615 }
616
617 static const IUnknownVtbl TestUnknown_Vtbl =
618 {
619 Test_IUnknown_QueryInterface,
620 Test_IUnknown_AddRef,
621 Test_IUnknown_Release,
622 };
623
624 struct test_stream
625 {
626 IStream IStream_iface;
627 LONG refs;
628 };
629
630 static inline struct test_stream *impl_from_IStream(IStream *iface)
631 {
632 return CONTAINING_RECORD(iface, struct test_stream, IStream_iface);
633 }
634
635 static HRESULT WINAPI Test_IStream_QueryInterface(IStream *iface,
636 REFIID riid, LPVOID *ppvObj)
637 {
638 if (ppvObj == NULL) return E_POINTER;
639
640 if (IsEqualIID(riid, &IID_IUnknown) ||
641 IsEqualIID(riid, &IID_IStream))
642 {
643 *ppvObj = iface;
644 IStream_AddRef(iface);
645 return S_OK;
646 }
647
648 *ppvObj = NULL;
649 return E_NOINTERFACE;
650 }
651
652 static ULONG WINAPI Test_IStream_AddRef(IStream *iface)
653 {
654 struct test_stream *This = impl_from_IStream(iface);
655 return InterlockedIncrement(&This->refs);
656 }
657
658 static ULONG WINAPI Test_IStream_Release(IStream *iface)
659 {
660 struct test_stream *This = impl_from_IStream(iface);
661 return InterlockedDecrement(&This->refs);
662 }
663
664 static const IStreamVtbl TestStream_Vtbl =
665 {
666 Test_IStream_QueryInterface,
667 Test_IStream_AddRef,
668 Test_IStream_Release
669 /* the rest can be NULLs */
670 };
671
672 static TestUnknown Test_Unknown = { {&TestUnknown_Vtbl}, 1 };
673 static TestUnknown Test_Unknown2 = { {&TestUnknown_Vtbl}, 1 };
674 static struct test_stream Test_Stream = { {&TestStream_Vtbl}, 1 };
675 static struct test_stream Test_Stream2 = { {&TestStream_Vtbl}, 1 };
676
677 ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG *, ULONG, ULONG, IUnknown *, REFIID);
678 unsigned char * __RPC_USER WdtpInterfacePointer_UserMarshal(ULONG *, ULONG, unsigned char *, IUnknown *, REFIID);
679 unsigned char * __RPC_USER WdtpInterfacePointer_UserUnmarshal(ULONG *, unsigned char *, IUnknown **, REFIID);
680
681 static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx, BOOL client, BOOL in, BOOL out)
682 {
683 USER_MARSHAL_CB umcb;
684 MIDL_STUB_MESSAGE stub_msg;
685 RPC_MESSAGE rpc_msg;
686 unsigned char *buffer, *buffer_end;
687 ULONG size;
688 IUnknown *unk;
689 IUnknown *unk2;
690 unsigned char *wireip;
691 HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, 0);
692 IStream *stm;
693 void *marshal_data;
694 LARGE_INTEGER zero;
695 ULARGE_INTEGER pos;
696 DWORD marshal_size;
697
698 /* shows that the WdtpInterfacePointer functions don't marshal anything for
699 * NULL pointers, so code using these functions must handle that case
700 * itself */
701
702 unk = NULL;
703 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, umcb_ctx);
704 size = WdtpInterfacePointer_UserSize(&umcb.Flags, ctx, 0, unk, &IID_IUnknown);
705 ok(size == 0, "size should be 0 bytes, not %d\n", size);
706 buffer = HeapAlloc(GetProcessHeap(), 0, size);
707 buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, ctx, buffer, unk, &IID_IUnknown);
708 ok(buffer_end == buffer, "buffer_end %p buffer %p\n", buffer_end, buffer);
709 HeapFree(GetProcessHeap(), 0, buffer);
710
711 /* Now for a non-NULL pointer. The marshalled data are two size DWORDS and then
712 the result of CoMarshalInterface called with the LOWORD of the ctx */
713
714 unk = &Test_Unknown.IUnknown_iface;
715 Test_Unknown.refs = 1;
716
717 CreateStreamOnHGlobal(h, TRUE, &stm);
718 CoMarshalInterface(stm, &IID_IUnknown, unk, LOWORD(ctx), NULL, MSHLFLAGS_NORMAL);
719 zero.QuadPart = 0;
720 IStream_Seek(stm, zero, STREAM_SEEK_CUR, &pos);
721 marshal_size = pos.u.LowPart;
722 marshal_data = GlobalLock(h);
723 todo_wine
724 ok(Test_Unknown.refs == 2, "got %d\n", Test_Unknown.refs);
725
726 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, umcb_ctx);
727 size = WdtpInterfacePointer_UserSize(&umcb.Flags, ctx, 0, unk, &IID_IUnknown);
728 ok(size >= marshal_size + 2 * sizeof(DWORD), "marshal size %x got %x\n", marshal_size, size);
729 buffer = HeapAlloc(GetProcessHeap(), 0, size);
730 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, umcb_ctx);
731 buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, ctx, buffer, unk, &IID_IUnknown);
732 todo_wine
733 ok(Test_Unknown.refs == 2, "got %d\n", Test_Unknown.refs);
734 wireip = buffer;
735
736 ok(buffer_end == buffer + marshal_size + 2 * sizeof(DWORD), "buffer_end %p buffer %p\n", buffer_end, buffer);
737
738 ok(*(DWORD *)wireip == marshal_size, "wireip + 0x0 should be %x instead of %x\n", marshal_size, *(DWORD *)wireip);
739 wireip += sizeof(DWORD);
740 ok(*(DWORD *)wireip == marshal_size, "wireip + 0x4 should be %x instead of %x\n", marshal_size, *(DWORD *)wireip);
741 wireip += sizeof(DWORD);
742
743 ok(!memcmp(marshal_data, wireip, marshal_size), "buffer mismatch\n");
744 GlobalUnlock(h);
745 zero.QuadPart = 0;
746 IStream_Seek(stm, zero, STREAM_SEEK_SET, NULL);
747 CoReleaseMarshalData(stm);
748 IStream_Release(stm);
749
750 Test_Unknown2.refs = 1;
751 unk2 = &Test_Unknown2.IUnknown_iface;
752 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, umcb_ctx);
753 umcb.pStubMsg->IsClient = client;
754 umcb.pStubMsg->fIsIn = in;
755 umcb.pStubMsg->fIsOut = out;
756
757 WdtpInterfacePointer_UserUnmarshal(&umcb.Flags, buffer, &unk2, &IID_IUnknown);
758 ok(unk2 != NULL, "IUnknown object didn't unmarshal properly\n");
759 ok(Test_Unknown.refs == 2, "got %d\n", Test_Unknown.refs);
760 ok(Test_Unknown2.refs == 0, "got %d\n", Test_Unknown2.refs);
761 HeapFree(GetProcessHeap(), 0, buffer);
762 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
763 IUnknown_Release(unk2);
764 }
765
766 static void test_marshal_WdtpInterfacePointer(void)
767 {
768 /*
769 * There are two places where we can pass the marshalling ctx: as
770 * part of the umcb and as a separate flag. The loword of that
771 * separate flag field is what matters.
772 */
773
774 /* All three are marshalled as inproc */
775 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_INPROC, 0,0,0);
776 marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_INPROC,0,0,0);
777 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_INPROC, 0xffff),0,0,0);
778
779 /* All three are marshalled as remote */
780 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,0,0);
781 marshal_WdtpInterfacePointer(MSHCTX_DIFFERENTMACHINE, MSHCTX_DIFFERENTMACHINE,0,0,0);
782 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MAKELONG(MSHCTX_DIFFERENTMACHINE, 0xffff),0,0,0);
783
784 /* Test different combinations of client, in and out */
785 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,0,1);
786 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,1,0);
787 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,0,1,1);
788 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,0,0);
789 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,0,1);
790 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,1,0);
791 marshal_WdtpInterfacePointer(MSHCTX_INPROC, MSHCTX_DIFFERENTMACHINE,1,1,1);
792 }
793
794 static void marshal_STGMEDIUM(BOOL client, BOOL in, BOOL out)
795 {
796 USER_MARSHAL_CB umcb;
797 MIDL_STUB_MESSAGE stub_msg;
798 RPC_MESSAGE rpc_msg;
799 unsigned char *buffer, *buffer_end, *expect_buffer, *expect_buffer_end;
800 ULONG size, expect_size;
801 STGMEDIUM med, med2;
802 IUnknown *unk = &Test_Unknown.IUnknown_iface;
803 IStream *stm = &Test_Stream.IStream_iface;
804
805 /* TYMED_NULL with pUnkForRelease */
806
807 Test_Unknown.refs = 1;
808
809 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
810 expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 2 * sizeof(DWORD), unk, &IID_IUnknown);
811 expect_buffer = HeapAlloc(GetProcessHeap(), 0, expect_size);
812 *(DWORD*)expect_buffer = TYMED_NULL;
813 *((DWORD*)expect_buffer + 1) = 0xdeadbeef;
814 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE);
815 expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer + 2 * sizeof(DWORD), unk, &IID_IUnknown);
816
817 med.tymed = TYMED_NULL;
818 U(med).pstg = NULL;
819 med.pUnkForRelease = unk;
820
821 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
822 size = STGMEDIUM_UserSize(&umcb.Flags, 0, &med);
823 ok(size == expect_size, "size %d should be %d bytes\n", size, expect_size);
824
825 buffer = HeapAlloc(GetProcessHeap(), 0, size);
826 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
827 buffer_end = STGMEDIUM_UserMarshal(&umcb.Flags, buffer, &med);
828 ok(buffer_end - buffer == expect_buffer_end - expect_buffer, "buffer size mismatch\n");
829 ok(*(DWORD*)buffer == TYMED_NULL, "got %08x\n", *(DWORD*)buffer);
830 ok(*((DWORD*)buffer+1) != 0, "got %08x\n", *((DWORD*)buffer+1));
831 ok(!memcmp(buffer+8, expect_buffer + 8, expect_buffer_end - expect_buffer - 8), "buffer mismatch\n");
832
833 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
834 umcb.pStubMsg->IsClient = client;
835 umcb.pStubMsg->fIsIn = in;
836 umcb.pStubMsg->fIsOut = out;
837
838 Test_Unknown2.refs = 1;
839 med2.tymed = TYMED_NULL;
840 U(med2).pstm = NULL;
841 med2.pUnkForRelease = &Test_Unknown2.IUnknown_iface;
842
843 STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2);
844
845 ok(med2.tymed == TYMED_NULL, "got tymed %x\n", med2.tymed);
846 ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n");
847 ok(Test_Unknown2.refs == 0, "got %d\n", Test_Unknown2.refs);
848
849 HeapFree(GetProcessHeap(), 0, buffer);
850 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
851 STGMEDIUM_UserFree(&umcb.Flags, &med2);
852
853 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE);
854 med2.tymed = TYMED_NULL;
855 U(med2).pstm = NULL;
856 med2.pUnkForRelease = NULL;
857 STGMEDIUM_UserUnmarshal(&umcb.Flags, expect_buffer, &med2);
858 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
859 STGMEDIUM_UserFree(&umcb.Flags, &med2);
860
861 ok(Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs);
862
863 HeapFree(GetProcessHeap(), 0, expect_buffer);
864
865 /* TYMED_ISTREAM with pUnkForRelease */
866
867 Test_Unknown.refs = 1;
868 Test_Stream.refs = 1;
869
870 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
871 expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 3 * sizeof(DWORD), (IUnknown*)stm, &IID_IStream);
872 expect_size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, expect_size, unk, &IID_IUnknown);
873
874 expect_buffer = HeapAlloc(GetProcessHeap(), 0, expect_size);
875 /* There may be a hole between the two interfaces so init the buffer to something */
876 memset(expect_buffer, 0xcc, expect_size);
877 *(DWORD*)expect_buffer = TYMED_ISTREAM;
878 *((DWORD*)expect_buffer + 1) = 0xdeadbeef;
879 *((DWORD*)expect_buffer + 2) = 0xcafe;
880 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE);
881 expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer + 3 * sizeof(DWORD), (IUnknown*)stm, &IID_IStream);
882 expect_buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, expect_buffer_end, unk, &IID_IUnknown);
883
884 med.tymed = TYMED_ISTREAM;
885 U(med).pstm = stm;
886 med.pUnkForRelease = unk;
887
888 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
889 size = STGMEDIUM_UserSize(&umcb.Flags, 0, &med);
890 ok(size == expect_size, "size %d should be %d bytes\n", size, expect_size);
891
892 buffer = HeapAlloc(GetProcessHeap(), 0, size);
893 memset(buffer, 0xcc, size);
894 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
895 buffer_end = STGMEDIUM_UserMarshal(&umcb.Flags, buffer, &med);
896 ok(buffer_end - buffer == expect_buffer_end - expect_buffer, "buffer size mismatch\n");
897 ok(*(DWORD*)buffer == TYMED_ISTREAM, "got %08x\n", *(DWORD*)buffer);
898 ok(*((DWORD*)buffer+1) != 0, "got %08x\n", *((DWORD*)buffer+1));
899 ok(*((DWORD*)buffer+2) != 0, "got %08x\n", *((DWORD*)buffer+2));
900 ok(!memcmp(buffer + 12, expect_buffer + 12, (buffer_end - buffer) - 12), "buffer mismatch\n");
901
902 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
903 umcb.pStubMsg->IsClient = client;
904 umcb.pStubMsg->fIsIn = in;
905 umcb.pStubMsg->fIsOut = out;
906
907 Test_Stream2.refs = 1;
908 Test_Unknown2.refs = 1;
909 med2.tymed = TYMED_ISTREAM;
910 U(med2).pstm = &Test_Stream2.IStream_iface;
911 med2.pUnkForRelease = &Test_Unknown2.IUnknown_iface;
912
913 STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2);
914
915 ok(med2.tymed == TYMED_ISTREAM, "got tymed %x\n", med2.tymed);
916 ok(U(med2).pstm != NULL, "Incorrectly unmarshalled\n");
917 ok(med2.pUnkForRelease != NULL, "Incorrectly unmarshalled\n");
918 ok(Test_Stream2.refs == 0, "got %d\n", Test_Stream2.refs);
919 ok(Test_Unknown2.refs == 0, "got %d\n", Test_Unknown2.refs);
920
921 HeapFree(GetProcessHeap(), 0, buffer);
922 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
923 STGMEDIUM_UserFree(&umcb.Flags, &med2);
924
925 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, expect_buffer, expect_size, MSHCTX_DIFFERENTMACHINE);
926 med2.tymed = TYMED_NULL;
927 U(med2).pstm = NULL;
928 med2.pUnkForRelease = NULL;
929 STGMEDIUM_UserUnmarshal(&umcb.Flags, expect_buffer, &med2);
930 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
931 STGMEDIUM_UserFree(&umcb.Flags, &med2);
932
933 ok(Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs);
934 ok(Test_Stream.refs == 1, "got %d\n", Test_Stream.refs);
935
936 HeapFree(GetProcessHeap(), 0, expect_buffer);
937
938 /* TYMED_ISTREAM = NULL with pUnkForRelease = NULL */
939
940 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
941 expect_size = 3 * sizeof(DWORD);
942
943 med.tymed = TYMED_ISTREAM;
944 U(med).pstm = NULL;
945 med.pUnkForRelease = NULL;
946
947 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
948 size = STGMEDIUM_UserSize(&umcb.Flags, 0, &med);
949 ok(size == expect_size, "size %d should be %d bytes\n", size, expect_size);
950
951 buffer = HeapAlloc(GetProcessHeap(), 0, size);
952 memset(buffer, 0xcc, size);
953 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
954 buffer_end = STGMEDIUM_UserMarshal(&umcb.Flags, buffer, &med);
955 ok(buffer_end - buffer == expect_size, "buffer size mismatch\n");
956 ok(*(DWORD*)buffer == TYMED_ISTREAM, "got %08x\n", *(DWORD*)buffer);
957 ok(*((DWORD*)buffer+1) == 0, "got %08x\n", *((DWORD*)buffer+1));
958 ok(*((DWORD*)buffer+2) == 0, "got %08x\n", *((DWORD*)buffer+2));
959
960 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
961 umcb.pStubMsg->IsClient = client;
962 umcb.pStubMsg->fIsIn = in;
963 umcb.pStubMsg->fIsOut = out;
964
965 Test_Stream2.refs = 1;
966 Test_Unknown2.refs = 1;
967 med2.tymed = TYMED_ISTREAM;
968 U(med2).pstm = &Test_Stream2.IStream_iface;
969 med2.pUnkForRelease = &Test_Unknown2.IUnknown_iface;
970
971 STGMEDIUM_UserUnmarshal(&umcb.Flags, buffer, &med2);
972
973 ok(med2.tymed == TYMED_ISTREAM, "got tymed %x\n", med2.tymed);
974 ok(U(med2).pstm == NULL, "Incorrectly unmarshalled\n");
975 ok(med2.pUnkForRelease == &Test_Unknown2.IUnknown_iface, "Incorrectly unmarshalled\n");
976 ok(Test_Stream2.refs == 0, "got %d\n", Test_Stream2.refs);
977 ok(Test_Unknown2.refs == 1, "got %d\n", Test_Unknown2.refs);
978
979 HeapFree(GetProcessHeap(), 0, buffer);
980 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
981 STGMEDIUM_UserFree(&umcb.Flags, &med2);
982 }
983
984 static void test_marshal_STGMEDIUM(void)
985 {
986 marshal_STGMEDIUM(0, 0, 0);
987 marshal_STGMEDIUM(0, 0, 1);
988 marshal_STGMEDIUM(0, 1, 0);
989 marshal_STGMEDIUM(0, 1, 1);
990 /* For Windows versions post 2003, client side, non-[in,out] STGMEDIUMs get zero-initialised.
991 However since inline stubs don't set fIsIn or fIsOut this behaviour would break
992 ref counting in GetDataHere_Proxy for example, as we'd end up not releasing the original
993 interface. For simplicity we don't test or implement this. */
994 marshal_STGMEDIUM(1, 1, 1);
995 }
996
997 static void test_marshal_SNB(void)
998 {
999 static const WCHAR str1W[] = {'s','t','r','i','n','g','1',0};
1000 static const WCHAR str2W[] = {'s','t','r','2',0};
1001 unsigned char *buffer, *src, *mbuf;
1002 MIDL_STUB_MESSAGE stub_msg;
1003 WCHAR **ptrW, *dataW;
1004 USER_MARSHAL_CB umcb;
1005 RPC_MESSAGE rpc_msg;
1006 RemSNB *wiresnb;
1007 SNB snb, snb2;
1008 ULONG size;
1009
1010 /* 4 bytes alignment */
1011 snb = NULL;
1012 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1013 size = SNB_UserSize(&umcb.Flags, 3, &snb);
1014 ok(size == 16, "Size should be 16, instead of %d\n", size);
1015
1016 /* NULL block */
1017 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1018 size = SNB_UserSize(&umcb.Flags, 0, &snb);
1019 ok(size == 12, "Size should be 12, instead of %d\n", size);
1020
1021 buffer = HeapAlloc(GetProcessHeap(), 0, size);
1022 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1023 mbuf = SNB_UserMarshal(&umcb.Flags, buffer, &snb);
1024 ok(mbuf == buffer + size, "got %p, %p\n", mbuf, buffer + size);
1025
1026 wiresnb = (RemSNB*)buffer;
1027 ok(wiresnb->ulCntStr == 0, "got %u\n", wiresnb->ulCntStr);
1028 ok(wiresnb->ulCntChar == 0, "got %u\n", wiresnb->ulCntChar);
1029 ok(*(ULONG*)wiresnb->rgString == 0, "got %u\n", *(ULONG*)wiresnb->rgString);
1030
1031 snb2 = NULL;
1032 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1033 SNB_UserUnmarshal(&umcb.Flags, buffer, &snb2);
1034 ok(snb2 == NULL, "got %p\n", snb2);
1035
1036 HeapFree(GetProcessHeap(), 0, buffer);
1037 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1038 SNB_UserFree(&umcb.Flags, &snb2);
1039
1040 /* block with actual data */
1041
1042 /* allocate source block, n+1 pointers first, then data */
1043 src = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR*)*3 + sizeof(str1W) + sizeof(str2W));
1044 ptrW = (WCHAR**)src;
1045 dataW = *ptrW = (WCHAR*)(src + 3*sizeof(WCHAR*));
1046 ptrW++;
1047 *ptrW = (WCHAR*)(src + 3*sizeof(WCHAR*) + sizeof(str1W));
1048 ptrW++;
1049 *ptrW = NULL;
1050 lstrcpyW(dataW, str1W);
1051 dataW += lstrlenW(str1W) + 1;
1052 lstrcpyW(dataW, str2W);
1053
1054 snb = (SNB)src;
1055 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1056 size = SNB_UserSize(&umcb.Flags, 0, &snb);
1057 ok(size == 38, "Size should be 38, instead of %d\n", size);
1058
1059 buffer = HeapAlloc(GetProcessHeap(), 0, size);
1060 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1061 SNB_UserMarshal(&umcb.Flags, buffer, &snb);
1062
1063 wiresnb = (RemSNB*)buffer;
1064 ok(wiresnb->ulCntStr == 13, "got %u\n", wiresnb->ulCntStr);
1065 ok(wiresnb->ulCntChar == 2, "got %u\n", wiresnb->ulCntChar);
1066 /* payload length is stored one more time, as ULONG */
1067 ok(*(ULONG*)wiresnb->rgString == wiresnb->ulCntStr, "got %u\n", *(ULONG*)wiresnb->rgString);
1068 dataW = &wiresnb->rgString[2];
1069 ok(!lstrcmpW(dataW, str1W), "marshalled string 0: %s\n", wine_dbgstr_w(dataW));
1070 dataW += sizeof(str1W)/sizeof(WCHAR);
1071 ok(!lstrcmpW(dataW, str2W), "marshalled string 1: %s\n", wine_dbgstr_w(dataW));
1072
1073 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1074
1075 g_expect_user_alloc = TRUE;
1076 snb2 = NULL;
1077 SNB_UserUnmarshal(&umcb.Flags, buffer, &snb2);
1078 g_expect_user_alloc = FALSE;
1079
1080 ptrW = snb2;
1081 ok(!lstrcmpW(*ptrW, str1W), "unmarshalled string 0: %s\n", wine_dbgstr_w(*ptrW));
1082 ptrW++;
1083 ok(!lstrcmpW(*ptrW, str2W), "unmarshalled string 1: %s\n", wine_dbgstr_w(*ptrW));
1084 ptrW++;
1085 ok(*ptrW == NULL, "expected terminating NULL ptr, got %p, start %p\n", *ptrW, snb2);
1086
1087 HeapFree(GetProcessHeap(), 0, buffer);
1088 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1089
1090 g_expect_user_free = TRUE;
1091 SNB_UserFree(&umcb.Flags, &snb2);
1092 g_expect_user_free = FALSE;
1093
1094 HeapFree(GetProcessHeap(), 0, src);
1095 }
1096
1097 static void test_marshal_HDC(void)
1098 {
1099 MIDL_STUB_MESSAGE stub_msg;
1100 HDC hdc = GetDC(0), hdc2;
1101 USER_MARSHAL_CB umcb;
1102 RPC_MESSAGE rpc_msg;
1103 unsigned char *buffer, *buffer_end;
1104 wireHDC wirehdc;
1105 ULONG size;
1106
1107 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1108 size = HDC_UserSize(&umcb.Flags, 1, &hdc);
1109 ok(size == 4 + sizeof(*wirehdc), "Wrong size %d\n", size);
1110
1111 buffer = HeapAlloc(GetProcessHeap(), 0, size);
1112 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1113 buffer_end = HDC_UserMarshal(&umcb.Flags, buffer + 1, &hdc);
1114 ok(buffer_end == buffer + 4 + sizeof(*wirehdc), "got %p buffer %p\n", buffer_end, buffer);
1115 wirehdc = (wireHDC)(buffer + 4);
1116 ok(wirehdc->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehdc->fContext);
1117 ok(wirehdc->u.hInproc == (LONG_PTR)hdc, "Marshaled value should be %p instead of %x\n", hdc, wirehdc->u.hRemote);
1118
1119 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1120 buffer_end = HDC_UserUnmarshal(&umcb.Flags, buffer + 1, &hdc2);
1121 ok(buffer_end == buffer + 4 + sizeof(*wirehdc), "got %p buffer %p\n", buffer_end, buffer);
1122 ok(hdc == hdc2, "Didn't unmarshal properly\n");
1123 HeapFree(GetProcessHeap(), 0, buffer);
1124
1125 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1126 HDC_UserFree(&umcb.Flags, &hdc2);
1127 ReleaseDC(0, hdc);
1128 }
1129
1130 static void test_marshal_HICON(void)
1131 {
1132 static const BYTE bmp_bits[1024];
1133 MIDL_STUB_MESSAGE stub_msg;
1134 HICON hIcon, hIcon2;
1135 USER_MARSHAL_CB umcb;
1136 RPC_MESSAGE rpc_msg;
1137 unsigned char *buffer, *buffer_end;
1138 wireHICON wirehicon;
1139 ULONG size;
1140
1141 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, bmp_bits);
1142 ok(hIcon != 0, "CreateIcon failed\n");
1143
1144 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1145 size = HICON_UserSize(&umcb.Flags, 1, &hIcon);
1146 ok(size == 4 + sizeof(*wirehicon), "Wrong size %d\n", size);
1147
1148 buffer = HeapAlloc(GetProcessHeap(), 0, size);
1149 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1150 buffer_end = HICON_UserMarshal(&umcb.Flags, buffer + 1, &hIcon);
1151 ok(buffer_end == buffer + 4 + sizeof(*wirehicon), "got %p buffer %p\n", buffer_end, buffer);
1152 wirehicon = (wireHICON)(buffer + 4);
1153 ok(wirehicon->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehicon->fContext);
1154 ok(wirehicon->u.hInproc == (LONG_PTR)hIcon, "Marshaled value should be %p instead of %x\n", hIcon, wirehicon->u.hRemote);
1155
1156 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1157 buffer_end = HICON_UserUnmarshal(&umcb.Flags, buffer + 1, &hIcon2);
1158 ok(buffer_end == buffer + 4 + sizeof(*wirehicon), "got %p buffer %p\n", buffer_end, buffer);
1159 ok(hIcon == hIcon2, "Didn't unmarshal properly\n");
1160 HeapFree(GetProcessHeap(), 0, buffer);
1161
1162 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1163 HICON_UserFree(&umcb.Flags, &hIcon2);
1164 DestroyIcon(hIcon);
1165 }
1166
1167 static void test_marshal_HBRUSH(void)
1168 {
1169 MIDL_STUB_MESSAGE stub_msg;
1170 HBRUSH hBrush, hBrush2;
1171 USER_MARSHAL_CB umcb;
1172 RPC_MESSAGE rpc_msg;
1173 unsigned char *buffer, *buffer_end;
1174 LOGBRUSH logbrush;
1175 wireHBRUSH wirehbrush;
1176 ULONG size;
1177
1178 logbrush.lbStyle = BS_SOLID;
1179 logbrush.lbColor = RGB(0, 0, 0);
1180 logbrush.lbHatch = 0;
1181
1182 hBrush = CreateBrushIndirect(&logbrush);
1183 ok(hBrush != 0, "CreateBrushIndirect failed\n");
1184
1185 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1186 size = HBRUSH_UserSize(&umcb.Flags, 1, &hBrush);
1187 ok(size == 4 + sizeof(*wirehbrush), "Wrong size %d\n", size);
1188
1189 buffer = HeapAlloc(GetProcessHeap(), 0, size);
1190 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1191 buffer_end = HBRUSH_UserMarshal(&umcb.Flags, buffer + 1, &hBrush);
1192 ok(buffer_end == buffer + 4 + sizeof(*wirehbrush), "got %p buffer %p\n", buffer_end, buffer);
1193 wirehbrush = (wireHBRUSH)(buffer + 4);
1194 ok(wirehbrush->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehbrush->fContext);
1195 ok(wirehbrush->u.hInproc == (LONG_PTR)hBrush, "Marshaled value should be %p instead of %x\n", hBrush, wirehbrush->u.hRemote);
1196
1197 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1198 buffer_end = HBRUSH_UserUnmarshal(&umcb.Flags, buffer + 1, &hBrush2);
1199 ok(buffer_end == buffer + 4 + sizeof(*wirehbrush), "got %p buffer %p\n", buffer_end, buffer);
1200 ok(hBrush == hBrush2, "Didn't unmarshal properly\n");
1201 HeapFree(GetProcessHeap(), 0, buffer);
1202
1203 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1204 HBRUSH_UserFree(&umcb.Flags, &hBrush2);
1205 DeleteObject(hBrush);
1206 }
1207
1208 static void test_marshal_HBITMAP(void)
1209 {
1210 static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize);
1211 static BYTE bmp_bits[1024];
1212 MIDL_STUB_MESSAGE stub_msg;
1213 HBITMAP hBitmap, hBitmap2;
1214 USER_MARSHAL_CB umcb;
1215 RPC_MESSAGE rpc_msg;
1216 unsigned char *buffer, *buffer_end;
1217 unsigned char bitmap[1024];
1218 ULONG size, bitmap_size;
1219
1220 hBitmap = CreateBitmap(16, 16, 1, 1, bmp_bits);
1221 ok(hBitmap != 0, "CreateBitmap failed\n");
1222 size = GetObjectA(hBitmap, sizeof(bitmap), bitmap);
1223 ok(size != 0, "GetObject failed\n");
1224 bitmap_size = GetBitmapBits(hBitmap, 0, NULL);
1225 ok(bitmap_size != 0, "GetBitmapBits failed\n");
1226
1227 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
1228 size = HBITMAP_UserSize(&umcb.Flags, 1, &hBitmap);
1229 ok(size == 0xc, "Wrong size %d\n", size);
1230 buffer = HeapAlloc(GetProcessHeap(), 0, size + 4);
1231 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC);
1232 buffer_end = HBITMAP_UserMarshal(&umcb.Flags, buffer + 1, &hBitmap);
1233 ok(buffer_end == buffer + 0xc, "HBITMAP_UserMarshal() returned wrong size %d\n", (LONG)(buffer_end - buffer));
1234 ok(*(ULONG *)(buffer + 0x4) == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", *(ULONG *)(buffer + 0x4));
1235 ok(*(ULONG *)(buffer + 0x8) == (ULONG)(ULONG_PTR)hBitmap, "wirestgm + 0x4 should be bitmap handle instead of 0x%08x\n", *(ULONG *)(buffer + 0x8));
1236
1237 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC);
1238 HBITMAP_UserUnmarshal(&umcb.Flags, buffer + 1, &hBitmap2);
1239 ok(hBitmap2 != NULL, "Didn't unmarshal properly\n");
1240 HeapFree(GetProcessHeap(), 0, buffer);
1241
1242 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
1243 HBITMAP_UserFree(&umcb.Flags, &hBitmap2);
1244
1245 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1246 size = HBITMAP_UserSize(&umcb.Flags, 1, &hBitmap);
1247 ok(size == 0x10 + header_size + bitmap_size ||
1248 broken(size == 0x14 + header_size + bitmap_size), /* Windows adds 4 extra (unused) bytes */
1249 "Wrong size %d\n", size);
1250
1251 buffer = HeapAlloc(GetProcessHeap(), 0, size + 4);
1252 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1253 buffer_end = HBITMAP_UserMarshal(&umcb.Flags, buffer + 1, &hBitmap);
1254 ok(buffer_end == buffer + 0x10 + header_size + bitmap_size, "HBITMAP_UserMarshal() returned wrong size %d\n", (LONG)(buffer_end - buffer));
1255 ok(*(ULONG *)(buffer + 0x4) == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)buffer);
1256 ok(*(ULONG *)(buffer + 0x8) == (ULONG)(ULONG_PTR)hBitmap, "wirestgm + 0x4 should be bitmap handle instead of 0x%08x\n", *(ULONG *)(buffer + 0x4));
1257 ok(*(ULONG *)(buffer + 0xc) == (ULONG)(ULONG_PTR)bitmap_size, "wirestgm + 0x8 should be bitmap size instead of 0x%08x\n", *(ULONG *)(buffer + 0x4));
1258 ok(!memcmp(buffer + 0x10, bitmap, header_size), "buffer mismatch\n");
1259 ok(!memcmp(buffer + 0x10 + header_size, bmp_bits, bitmap_size), "buffer mismatch\n");
1260
1261 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL);
1262 HBITMAP_UserUnmarshal(&umcb.Flags, buffer + 1, &hBitmap2);
1263 ok(hBitmap2 != NULL, "Didn't unmarshal properly\n");
1264 HeapFree(GetProcessHeap(), 0, buffer);
1265
1266 init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL);
1267 HBITMAP_UserFree(&umcb.Flags, &hBitmap2);
1268 DeleteObject(hBitmap);
1269 }
1270
1271 struct obj
1272 {
1273 IDataObject IDataObject_iface;
1274 };
1275
1276 static HRESULT WINAPI obj_QueryInterface(IDataObject *iface, REFIID iid, void **obj)
1277 {
1278 *obj = NULL;
1279
1280 if (IsEqualGUID(iid, &IID_IUnknown) ||
1281 IsEqualGUID(iid, &IID_IDataObject))
1282 *obj = iface;
1283
1284 if (*obj)
1285 {
1286 IDataObject_AddRef(iface);
1287 return S_OK;
1288 }
1289
1290 return E_NOINTERFACE;
1291 }
1292
1293 static ULONG WINAPI obj_AddRef(IDataObject *iface)
1294 {
1295 return 2;
1296 }
1297
1298 static ULONG WINAPI obj_Release(IDataObject *iface)
1299 {
1300 return 1;
1301 }
1302
1303 static HRESULT WINAPI obj_DO_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1304 STGMEDIUM *med)
1305 {
1306 ok( med->pUnkForRelease == NULL, "got %p\n", med->pUnkForRelease );
1307
1308 if (fmt->cfFormat == 2)
1309 {
1310 IStream_Release(U(med)->pstm);
1311 U(med)->pstm = &Test_Stream2.IStream_iface;
1312 }
1313
1314 return S_OK;
1315 }
1316
1317 static const IDataObjectVtbl obj_data_object_vtbl =
1318 {
1319 obj_QueryInterface,
1320 obj_AddRef,
1321 obj_Release,
1322 NULL, /* GetData */
1323 obj_DO_GetDataHere,
1324 NULL, /* QueryGetData */
1325 NULL, /* GetCanonicalFormatEtc */
1326 NULL, /* SetData */
1327 NULL, /* EnumFormatEtc */
1328 NULL, /* DAdvise */
1329 NULL, /* DUnadvise */
1330 NULL /* EnumDAdvise */
1331 };
1332
1333 static struct obj obj =
1334 {
1335 {&obj_data_object_vtbl}
1336 };
1337
1338 static void test_GetDataHere_Proxy(void)
1339 {
1340 HRESULT hr;
1341 IStream *stm;
1342 HANDLE thread;
1343 DWORD tid;
1344 static const LARGE_INTEGER zero;
1345 IDataObject *data;
1346 FORMATETC fmt;
1347 STGMEDIUM med;
1348
1349 hr = CreateStreamOnHGlobal( NULL, TRUE, &stm );
1350 ok( hr == S_OK, "got %08x\n", hr );
1351 tid = start_host_object2( stm, &IID_IDataObject, (IUnknown *)&obj.IDataObject_iface, MSHLFLAGS_NORMAL, NULL, &thread );
1352
1353 IStream_Seek( stm, zero, STREAM_SEEK_SET, NULL );
1354 hr = CoUnmarshalInterface( stm, &IID_IDataObject, (void **)&data );
1355 ok( hr == S_OK, "got %08x\n", hr );
1356 IStream_Release( stm );
1357
1358 Test_Stream.refs = 1;
1359 Test_Stream2.refs = 1;
1360 Test_Unknown.refs = 1;
1361
1362 fmt.cfFormat = 1;
1363 fmt.ptd = NULL;
1364 fmt.dwAspect = DVASPECT_CONTENT;
1365 fmt.lindex = -1;
1366 U(med).pstm = NULL;
1367 med.pUnkForRelease = &Test_Unknown.IUnknown_iface;
1368
1369 fmt.tymed = med.tymed = TYMED_NULL;
1370 hr = IDataObject_GetDataHere( data, &fmt, &med );
1371 ok( hr == DV_E_TYMED, "got %08x\n", hr );
1372
1373 for (fmt.tymed = TYMED_HGLOBAL; fmt.tymed <= TYMED_ENHMF; fmt.tymed <<= 1)
1374 {
1375 med.tymed = fmt.tymed;
1376 hr = IDataObject_GetDataHere( data, &fmt, &med );
1377 ok( hr == (fmt.tymed <= TYMED_ISTORAGE ? S_OK : DV_E_TYMED), "got %08x for tymed %d\n", hr, fmt.tymed );
1378 ok( Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs );
1379 }
1380
1381 fmt.tymed = TYMED_ISTREAM;
1382 med.tymed = TYMED_ISTORAGE;
1383 hr = IDataObject_GetDataHere( data, &fmt, &med );
1384 ok( hr == DV_E_TYMED, "got %08x\n", hr );
1385
1386 fmt.tymed = med.tymed = TYMED_ISTREAM;
1387 U(med).pstm = &Test_Stream.IStream_iface;
1388 med.pUnkForRelease = &Test_Unknown.IUnknown_iface;
1389
1390 hr = IDataObject_GetDataHere( data, &fmt, &med );
1391 ok( hr == S_OK, "got %08x\n", hr );
1392
1393 ok( U(med).pstm == &Test_Stream.IStream_iface, "stm changed\n" );
1394 ok( med.pUnkForRelease == &Test_Unknown.IUnknown_iface, "punk changed\n" );
1395
1396 ok( Test_Stream.refs == 1, "got %d\n", Test_Stream.refs );
1397 ok( Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs );
1398
1399 fmt.cfFormat = 2;
1400 fmt.tymed = med.tymed = TYMED_ISTREAM;
1401 U(med).pstm = &Test_Stream.IStream_iface;
1402 med.pUnkForRelease = &Test_Unknown.IUnknown_iface;
1403
1404 hr = IDataObject_GetDataHere( data, &fmt, &med );
1405 ok( hr == S_OK, "got %08x\n", hr );
1406
1407 ok( U(med).pstm == &Test_Stream.IStream_iface, "stm changed\n" );
1408 ok( med.pUnkForRelease == &Test_Unknown.IUnknown_iface, "punk changed\n" );
1409
1410 ok( Test_Stream.refs == 1, "got %d\n", Test_Stream.refs );
1411 ok( Test_Unknown.refs == 1, "got %d\n", Test_Unknown.refs );
1412 ok( Test_Stream2.refs == 0, "got %d\n", Test_Stream2.refs );
1413
1414 IDataObject_Release( data );
1415 end_host_object( tid, thread );
1416 }
1417
1418 START_TEST(usrmarshal)
1419 {
1420 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1421
1422 test_marshal_CLIPFORMAT();
1423 test_marshal_HWND();
1424 test_marshal_HGLOBAL();
1425 test_marshal_HENHMETAFILE();
1426 test_marshal_HMETAFILE();
1427 test_marshal_HMETAFILEPICT();
1428 test_marshal_WdtpInterfacePointer();
1429 test_marshal_STGMEDIUM();
1430 test_marshal_SNB();
1431 test_marshal_HDC();
1432 test_marshal_HICON();
1433 test_marshal_HBRUSH();
1434 test_marshal_HBITMAP();
1435
1436 test_GetDataHere_Proxy();
1437
1438 CoUninitialize();
1439 }