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