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