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 }
1352