1 /*
2 * Marshaling Tests
3 *
4 * Copyright 2004 Robert Shearman
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_DCOM
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "olectl.h"
32 #include "shlguid.h"
33 #include "shobjidl.h"
34
35 #include "wine/test.h"
36 #include "wine/heap.h"
37
38 #define DEFINE_EXPECT(func) \
39 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
40
41 #define SET_EXPECT(func) \
42 expect_ ## func = TRUE
43
44 #define CHECK_EXPECT2(func) \
45 do { \
46 ok(expect_ ##func, "unexpected call " #func "\n"); \
47 called_ ## func = TRUE; \
48 }while(0)
49
50 #define CHECK_EXPECT(func) \
51 do { \
52 CHECK_EXPECT2(func); \
53 expect_ ## func = FALSE; \
54 }while(0)
55
56 #define CHECK_CALLED(func) \
57 do { \
58 ok(called_ ## func, "expected " #func "\n"); \
59 expect_ ## func = called_ ## func = FALSE; \
60 }while(0)
61
62 static const GUID CLSID_WineTestPSFactoryBuffer = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
63 static const GUID CLSID_DfMarshal = { 0x0000030b, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
64
65 /* functions that are not present on all versions of Windows */
66 static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
67 static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID);
68
69 /* helper macros to make tests a bit leaner */
70 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
71 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
72 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
73 #define ok_non_zero_external_conn() do {if (with_external_conn) ok(external_connections, "got no external connections\n");} while(0);
74 #define ok_zero_external_conn() do {if (with_external_conn) ok(!external_connections, "got %d external connections\n", external_connections);} while(0);
75 #define ok_last_release_closes(b) do {if (with_external_conn) ok(last_release_closes == b, "got %d expected %d\n", last_release_closes, b);} while(0);
76
77 #define OBJREF_SIGNATURE (0x574f454d)
78 #define OBJREF_STANDARD (0x1)
79 #define OBJREF_CUSTOM (0x4)
80
81 typedef struct tagDUALSTRINGARRAY {
82 unsigned short wNumEntries;
83 unsigned short wSecurityOffset;
84 unsigned short aStringArray[1];
85 } DUALSTRINGARRAY;
86
87 typedef UINT64 OXID;
88 typedef UINT64 OID;
89 typedef GUID IPID;
90
91 typedef struct tagSTDOBJREF {
92 ULONG flags;
93 ULONG cPublicRefs;
94 OXID oxid;
95 OID oid;
96 IPID ipid;
97 } STDOBJREF;
98
99 typedef struct tagOBJREF {
100 ULONG signature;
101 ULONG flags;
102 GUID iid;
103 union {
104 struct OR_STANDARD {
105 STDOBJREF std;
106 DUALSTRINGARRAY saResAddr;
107 } u_standard;
108 struct OR_HANDLER {
109 STDOBJREF std;
110 CLSID clsid;
111 DUALSTRINGARRAY saResAddr;
112 } u_handler;
113 struct OR_CUSTOM {
114 CLSID clsid;
115 ULONG cbExtension;
116 ULONG size;
117 byte *pData;
118 } u_custom;
119 } u_objref;
120 } OBJREF;
121
122 static const IID IID_IWineTest =
123 {
124 0x5201163f,
125 0x8164,
126 0x4fd0,
127 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
128 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
129
130 static const IID IID_IRemUnknown =
131 {
132 0x00000131,
133 0x0000,
134 0x0000,
135 {0xc0,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
136 };
137
138 #define EXTENTID_WineTest IID_IWineTest
139 #define CLSID_WineTest IID_IWineTest
140
141 static const CLSID CLSID_WineOOPTest =
142 {
143 0x5201163f,
144 0x8164,
145 0x4fd0,
146 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
147 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
148
test_cocreateinstance_proxy(void)149 static void test_cocreateinstance_proxy(void)
150 {
151 IUnknown *pProxy;
152 IMultiQI *pMQI;
153 HRESULT hr;
154
155 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
156
157 hr = CoCreateInstance(&CLSID_ShellDesktop, NULL, CLSCTX_INPROC, &IID_IUnknown, (void **)&pProxy);
158 ok_ole_success(hr, CoCreateInstance);
159 hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (void **)&pMQI);
160 ok(hr == S_OK, "created object is not a proxy, so was created in the wrong apartment\n");
161 if (hr == S_OK)
162 IMultiQI_Release(pMQI);
163 IUnknown_Release(pProxy);
164
165 CoUninitialize();
166 }
167
168 static const LARGE_INTEGER ullZero;
169 static LONG cLocks;
170
LockModule(void)171 static void LockModule(void)
172 {
173 InterlockedIncrement(&cLocks);
174 }
175
UnlockModule(void)176 static void UnlockModule(void)
177 {
178 InterlockedDecrement(&cLocks);
179 }
180
181 static BOOL with_external_conn;
182 static DWORD external_connections;
183 static BOOL last_release_closes;
184
ExternalConnection_QueryInterface(IExternalConnection * iface,REFIID riid,void ** ppv)185 static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv)
186 {
187 ok(0, "unexpected call\n");
188 *ppv = NULL;
189 return E_NOINTERFACE;
190 }
191
ExternalConnection_AddRef(IExternalConnection * iface)192 static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface)
193 {
194 return 2;
195 }
196
ExternalConnection_Release(IExternalConnection * iface)197 static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface)
198 {
199 return 1;
200 }
201
ExternalConnection_AddConnection(IExternalConnection * iface,DWORD extconn,DWORD reserved)202 static DWORD WINAPI ExternalConnection_AddConnection(IExternalConnection *iface, DWORD extconn, DWORD reserved)
203 {
204 trace("add connection\n");
205 return ++external_connections;
206 }
207
208
ExternalConnection_ReleaseConnection(IExternalConnection * iface,DWORD extconn,DWORD reserved,BOOL fLastReleaseCloses)209 static DWORD WINAPI ExternalConnection_ReleaseConnection(IExternalConnection *iface, DWORD extconn,
210 DWORD reserved, BOOL fLastReleaseCloses)
211 {
212 trace("release connection %d\n", fLastReleaseCloses);
213 last_release_closes = fLastReleaseCloses;
214 return --external_connections;
215 }
216
217 static const IExternalConnectionVtbl ExternalConnectionVtbl = {
218 ExternalConnection_QueryInterface,
219 ExternalConnection_AddRef,
220 ExternalConnection_Release,
221 ExternalConnection_AddConnection,
222 ExternalConnection_ReleaseConnection
223 };
224
225 static IExternalConnection ExternalConnection = { &ExternalConnectionVtbl };
226
227
Test_IUnknown_QueryInterface(LPUNKNOWN iface,REFIID riid,LPVOID * ppvObj)228 static HRESULT WINAPI Test_IUnknown_QueryInterface(
229 LPUNKNOWN iface,
230 REFIID riid,
231 LPVOID *ppvObj)
232 {
233 if (ppvObj == NULL) return E_POINTER;
234
235 if (IsEqualGUID(riid, &IID_IUnknown))
236 {
237 *ppvObj = iface;
238 IUnknown_AddRef(iface);
239 return S_OK;
240 }
241
242 *ppvObj = NULL;
243 return E_NOINTERFACE;
244 }
245
Test_IUnknown_AddRef(LPUNKNOWN iface)246 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
247 {
248 LockModule();
249 return 2; /* non-heap-based object */
250 }
251
Test_IUnknown_Release(LPUNKNOWN iface)252 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
253 {
254 UnlockModule();
255 return 1; /* non-heap-based object */
256 }
257
258 static const IUnknownVtbl TestUnknown_Vtbl =
259 {
260 Test_IUnknown_QueryInterface,
261 Test_IUnknown_AddRef,
262 Test_IUnknown_Release,
263 };
264
265 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
266
TestCrash_IUnknown_Release(LPUNKNOWN iface)267 static ULONG WINAPI TestCrash_IUnknown_Release(LPUNKNOWN iface)
268 {
269 UnlockModule();
270 if(!cLocks) {
271 trace("crashing...\n");
272 *(int**)0xc = 0;
273 }
274 return 1; /* non-heap-based object */
275 }
276
277 static const IUnknownVtbl TestCrashUnknown_Vtbl =
278 {
279 Test_IUnknown_QueryInterface,
280 Test_IUnknown_AddRef,
281 TestCrash_IUnknown_Release,
282 };
283
284 static IUnknown TestCrash_Unknown = { &TestCrashUnknown_Vtbl };
285
Test_IClassFactory_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID * ppvObj)286 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
287 LPCLASSFACTORY iface,
288 REFIID riid,
289 LPVOID *ppvObj)
290 {
291 if (ppvObj == NULL) return E_POINTER;
292
293 if (IsEqualGUID(riid, &IID_IUnknown) ||
294 IsEqualGUID(riid, &IID_IClassFactory) ||
295 /* the only other interface Wine is currently able to marshal (for testing two proxies) */
296 IsEqualGUID(riid, &IID_IRemUnknown))
297 {
298 *ppvObj = iface;
299 IClassFactory_AddRef(iface);
300 return S_OK;
301 }
302
303 if (with_external_conn && IsEqualGUID(riid, &IID_IExternalConnection))
304 {
305 *ppvObj = &ExternalConnection;
306 return S_OK;
307 }
308
309 *ppvObj = NULL;
310 return E_NOINTERFACE;
311 }
312
Test_IClassFactory_AddRef(LPCLASSFACTORY iface)313 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
314 {
315 LockModule();
316 return 2; /* non-heap-based object */
317 }
318
Test_IClassFactory_Release(LPCLASSFACTORY iface)319 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
320 {
321 UnlockModule();
322 return 1; /* non-heap-based object */
323 }
324
Test_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)325 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
326 LPCLASSFACTORY iface,
327 LPUNKNOWN pUnkOuter,
328 REFIID riid,
329 LPVOID *ppvObj)
330 {
331 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
332 return IUnknown_QueryInterface(&Test_Unknown, riid, ppvObj);
333 }
334
Test_IClassFactory_LockServer(LPCLASSFACTORY iface,BOOL fLock)335 static HRESULT WINAPI Test_IClassFactory_LockServer(
336 LPCLASSFACTORY iface,
337 BOOL fLock)
338 {
339 return S_OK;
340 }
341
342 static const IClassFactoryVtbl TestClassFactory_Vtbl =
343 {
344 Test_IClassFactory_QueryInterface,
345 Test_IClassFactory_AddRef,
346 Test_IClassFactory_Release,
347 Test_IClassFactory_CreateInstance,
348 Test_IClassFactory_LockServer
349 };
350
351 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
352
353 DEFINE_EXPECT(Invoke);
354 DEFINE_EXPECT(CreateStub);
355 DEFINE_EXPECT(CreateProxy);
356 DEFINE_EXPECT(GetWindow);
357 DEFINE_EXPECT(Disconnect);
358
OleWindow_QueryInterface(IOleWindow * iface,REFIID riid,void ** ppv)359 static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv)
360 {
361 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
362 *ppv = NULL;
363 return E_NOINTERFACE;
364 }
365
OleWindow_AddRef(IOleWindow * iface)366 static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
367 {
368 return 2;
369 }
370
OleWindow_Release(IOleWindow * iface)371 static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
372 {
373 return 1;
374 }
375
OleWindow_GetWindow(IOleWindow * iface,HWND * hwnd)376 static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
377 {
378 CHECK_EXPECT(GetWindow);
379 *hwnd = (HWND)0xdeadbeef;
380 return S_OK;
381 }
382
383 static const IOleWindowVtbl OleWindowVtbl = {
384 OleWindow_QueryInterface,
385 OleWindow_AddRef,
386 OleWindow_Release,
387 OleWindow_GetWindow,
388 /* not needed */
389 };
390
391 static IOleWindow Test_OleWindow = { &OleWindowVtbl };
392
OleClientSite_QueryInterface(IOleClientSite * iface,REFIID riid,void ** ppv)393 static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
394 {
395 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleClientSite))
396 *ppv = iface;
397 else if (IsEqualGUID(riid, &IID_IOleWindow))
398 *ppv = &Test_OleWindow;
399 else
400 {
401 *ppv = NULL;
402 return E_NOINTERFACE;
403 }
404
405 IUnknown_AddRef((IUnknown*)*ppv);
406 return S_OK;
407 }
408
OleClientSite_AddRef(IOleClientSite * iface)409 static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface)
410 {
411 return 2;
412 }
413
OleClientSite_Release(IOleClientSite * iface)414 static ULONG WINAPI OleClientSite_Release(IOleClientSite *iface)
415 {
416 return 1;
417 }
418
419 static const IOleClientSiteVtbl OleClientSiteVtbl = {
420 OleClientSite_QueryInterface,
421 OleClientSite_AddRef,
422 OleClientSite_Release,
423 /* we don't need the rest, we never call it */
424 };
425
426 static IOleClientSite Test_OleClientSite = { &OleClientSiteVtbl };
427
428 typedef struct {
429 IRpcStubBuffer IRpcStubBuffer_iface;
430 LONG ref;
431 IRpcStubBuffer *buffer;
432 } StubBufferWrapper;
433
impl_from_IRpcStubBuffer(IRpcStubBuffer * iface)434 static StubBufferWrapper *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
435 {
436 return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface);
437 }
438
RpcStubBuffer_QueryInterface(IRpcStubBuffer * iface,REFIID riid,void ** ppv)439 static HRESULT WINAPI RpcStubBuffer_QueryInterface(IRpcStubBuffer *iface, REFIID riid, void **ppv)
440 {
441 StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
442
443 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRpcStubBuffer, riid)) {
444 *ppv = &This->IRpcStubBuffer_iface;
445 }else {
446 *ppv = NULL;
447 return E_NOINTERFACE;
448 }
449
450 IUnknown_AddRef((IUnknown*)*ppv);
451 return S_OK;
452 }
453
RpcStubBuffer_AddRef(IRpcStubBuffer * iface)454 static ULONG WINAPI RpcStubBuffer_AddRef(IRpcStubBuffer *iface)
455 {
456 StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
457 return InterlockedIncrement(&This->ref);
458 }
459
RpcStubBuffer_Release(IRpcStubBuffer * iface)460 static ULONG WINAPI RpcStubBuffer_Release(IRpcStubBuffer *iface)
461 {
462 StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
463 LONG ref = InterlockedDecrement(&This->ref);
464 if(!ref) {
465 IRpcStubBuffer_Release(This->buffer);
466 heap_free(This);
467 }
468 return ref;
469 }
470
RpcStubBuffer_Connect(IRpcStubBuffer * iface,IUnknown * pUnkServer)471 static HRESULT WINAPI RpcStubBuffer_Connect(IRpcStubBuffer *iface, IUnknown *pUnkServer)
472 {
473 ok(0, "unexpected call\n");
474 return E_NOTIMPL;
475 }
476
RpcStubBuffer_Disconnect(IRpcStubBuffer * iface)477 static void WINAPI RpcStubBuffer_Disconnect(IRpcStubBuffer *iface)
478 {
479 CHECK_EXPECT(Disconnect);
480 }
481
RpcStubBuffer_Invoke(IRpcStubBuffer * iface,RPCOLEMESSAGE * _prpcmsg,IRpcChannelBuffer * _pRpcChannelBuffer)482 static HRESULT WINAPI RpcStubBuffer_Invoke(IRpcStubBuffer *iface, RPCOLEMESSAGE *_prpcmsg,
483 IRpcChannelBuffer *_pRpcChannelBuffer)
484 {
485 StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
486 void *dest_context_data;
487 DWORD dest_context;
488 HRESULT hr;
489
490 CHECK_EXPECT(Invoke);
491
492 hr = IRpcChannelBuffer_GetDestCtx(_pRpcChannelBuffer, &dest_context, &dest_context_data);
493 ok(hr == S_OK, "GetDestCtx failed: %08x\n", hr);
494 ok(dest_context == MSHCTX_INPROC, "desc_context = %x\n", dest_context);
495 ok(!dest_context_data, "desc_context_data = %p\n", dest_context_data);
496
497 return IRpcStubBuffer_Invoke(This->buffer, _prpcmsg, _pRpcChannelBuffer);
498 }
499
RpcStubBuffer_IsIIDSupported(IRpcStubBuffer * iface,REFIID riid)500 static IRpcStubBuffer *WINAPI RpcStubBuffer_IsIIDSupported(IRpcStubBuffer *iface, REFIID riid)
501 {
502 ok(0, "unexpected call\n");
503 return NULL;
504 }
505
RpcStubBuffer_CountRefs(IRpcStubBuffer * iface)506 static ULONG WINAPI RpcStubBuffer_CountRefs(IRpcStubBuffer *iface)
507 {
508 ok(0, "unexpected call\n");
509 return E_NOTIMPL;
510 }
511
RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer * iface,void ** ppv)512 static HRESULT WINAPI RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer *iface, void **ppv)
513 {
514 ok(0, "unexpected call\n");
515 return E_NOTIMPL;
516 }
517
RpcStubBuffer_DebugServerRelease(IRpcStubBuffer * iface,void * pv)518 static void WINAPI RpcStubBuffer_DebugServerRelease(IRpcStubBuffer *iface, void *pv)
519 {
520 ok(0, "unexpected call\n");
521 }
522
523 static const IRpcStubBufferVtbl RpcStubBufferVtbl = {
524 RpcStubBuffer_QueryInterface,
525 RpcStubBuffer_AddRef,
526 RpcStubBuffer_Release,
527 RpcStubBuffer_Connect,
528 RpcStubBuffer_Disconnect,
529 RpcStubBuffer_Invoke,
530 RpcStubBuffer_IsIIDSupported,
531 RpcStubBuffer_CountRefs,
532 RpcStubBuffer_DebugServerQueryInterface,
533 RpcStubBuffer_DebugServerRelease
534 };
535
536 static IPSFactoryBuffer *ps_factory_buffer;
537
PSFactoryBuffer_QueryInterface(IPSFactoryBuffer * iface,REFIID riid,void ** ppv)538 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv)
539 {
540 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPSFactoryBuffer))
541 *ppv = iface;
542 else
543 {
544 *ppv = NULL;
545 return E_NOINTERFACE;
546 }
547 IUnknown_AddRef((IUnknown*)*ppv);
548 return S_OK;
549 }
550
PSFactoryBuffer_AddRef(IPSFactoryBuffer * iface)551 static ULONG WINAPI PSFactoryBuffer_AddRef(IPSFactoryBuffer *iface)
552 {
553 return 2;
554 }
555
PSFactoryBuffer_Release(IPSFactoryBuffer * iface)556 static ULONG WINAPI PSFactoryBuffer_Release(IPSFactoryBuffer *iface)
557 {
558 return 1;
559 }
560
PSFactoryBuffer_CreateProxy(IPSFactoryBuffer * iface,IUnknown * outer,REFIID riid,IRpcProxyBuffer ** ppProxy,void ** ppv)561 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(IPSFactoryBuffer *iface, IUnknown *outer,
562 REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv)
563 {
564 CHECK_EXPECT(CreateProxy);
565 return IPSFactoryBuffer_CreateProxy(ps_factory_buffer, outer, riid, ppProxy, ppv);
566 }
567
PSFactoryBuffer_CreateStub(IPSFactoryBuffer * iface,REFIID riid,IUnknown * server,IRpcStubBuffer ** ppStub)568 static HRESULT WINAPI PSFactoryBuffer_CreateStub(IPSFactoryBuffer *iface, REFIID riid,
569 IUnknown *server, IRpcStubBuffer **ppStub)
570 {
571 StubBufferWrapper *stub;
572 HRESULT hr;
573
574 CHECK_EXPECT(CreateStub);
575
576 ok(server == (IUnknown*)&Test_OleClientSite, "unexpected server %p\n", server);
577
578 stub = heap_alloc(sizeof(*stub));
579 stub->IRpcStubBuffer_iface.lpVtbl = &RpcStubBufferVtbl;
580 stub->ref = 1;
581
582 hr = IPSFactoryBuffer_CreateStub(ps_factory_buffer, riid, server, &stub->buffer);
583 ok(hr == S_OK, "CreateStub failed: %08x\n", hr);
584
585 *ppStub = &stub->IRpcStubBuffer_iface;
586 return S_OK;
587 }
588
589 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
590 {
591 PSFactoryBuffer_QueryInterface,
592 PSFactoryBuffer_AddRef,
593 PSFactoryBuffer_Release,
594 PSFactoryBuffer_CreateProxy,
595 PSFactoryBuffer_CreateStub
596 };
597
598 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
599
600 #define RELEASEMARSHALDATA WM_USER
601
602 struct host_object_data
603 {
604 IStream *stream;
605 const IID *iid;
606 IUnknown *object;
607 MSHLFLAGS marshal_flags;
608 IMessageFilter *filter;
609 IUnknown *register_object;
610 const CLSID *register_clsid;
611 HANDLE marshal_event;
612 };
613
614 #ifndef __REACTOS__ /* FIXME: Inspect */
615 static IPSFactoryBuffer PSFactoryBuffer;
616 #endif
617
host_object_proc(LPVOID p)618 static DWORD CALLBACK host_object_proc(LPVOID p)
619 {
620 struct host_object_data *data = p;
621 DWORD registration_key;
622 HRESULT hr;
623 MSG msg;
624
625 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
626
627 if(data->register_object) {
628 hr = CoRegisterClassObject(data->register_clsid, data->register_object,
629 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key);
630 ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
631 }
632
633 if (data->filter)
634 {
635 IMessageFilter * prev_filter = NULL;
636 hr = CoRegisterMessageFilter(data->filter, &prev_filter);
637 if (prev_filter) IMessageFilter_Release(prev_filter);
638 ok_ole_success(hr, CoRegisterMessageFilter);
639 }
640
641 hr = CoMarshalInterface(data->stream, data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
642 ok_ole_success(hr, CoMarshalInterface);
643
644 /* force the message queue to be created before signaling parent thread */
645 PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
646
647 SetEvent(data->marshal_event);
648
649 while (GetMessageA(&msg, NULL, 0, 0))
650 {
651 if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
652 {
653 CoReleaseMarshalData(data->stream);
654 SetEvent((HANDLE)msg.lParam);
655 }
656 else
657 DispatchMessageA(&msg);
658 }
659
660 HeapFree(GetProcessHeap(), 0, data);
661
662 CoUninitialize();
663
664 return hr;
665 }
666
start_host_object2(struct host_object_data * object_data,HANDLE * thread)667 static DWORD start_host_object2(struct host_object_data *object_data, HANDLE *thread)
668 {
669 DWORD tid = 0;
670 struct host_object_data *data;
671
672 data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
673 *data = *object_data;
674 data->marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
675 *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
676
677 /* wait for marshaling to complete before returning */
678 ok( !WaitForSingleObject(data->marshal_event, 10000), "wait timed out\n" );
679 CloseHandle(data->marshal_event);
680
681 return tid;
682 }
683
start_host_object(IStream * stream,REFIID riid,IUnknown * object,MSHLFLAGS marshal_flags,HANDLE * thread)684 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
685 {
686 struct host_object_data object_data = { stream, riid, object, marshal_flags };
687 return start_host_object2(&object_data, thread);
688 }
689
690 /* asks thread to release the marshal data because it has to be done by the
691 * same thread that marshaled the interface in the first place. */
release_host_object(DWORD tid,WPARAM wp)692 static void release_host_object(DWORD tid, WPARAM wp)
693 {
694 HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
695 PostThreadMessageA(tid, RELEASEMARSHALDATA, wp, (LPARAM)event);
696 ok( !WaitForSingleObject(event, 10000), "wait timed out\n" );
697 CloseHandle(event);
698 }
699
end_host_object(DWORD tid,HANDLE thread)700 static void end_host_object(DWORD tid, HANDLE thread)
701 {
702 BOOL ret = PostThreadMessageA(tid, WM_QUIT, 0, 0);
703 ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
704 /* be careful of races - don't return until hosting thread has terminated */
705 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
706 CloseHandle(thread);
707 }
708
709 /* tests failure case of interface not having a marshaler specified in the
710 * registry */
test_no_marshaler(void)711 static void test_no_marshaler(void)
712 {
713 IStream *pStream;
714 HRESULT hr;
715
716 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
717 ok_ole_success(hr, CreateStreamOnHGlobal);
718 hr = CoMarshalInterface(pStream, &IID_IWineTest, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
719 ok(hr == E_NOINTERFACE, "CoMarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
720
721 IStream_Release(pStream);
722 }
723
724 /* tests normal marshal and then release without unmarshaling */
test_normal_marshal_and_release(void)725 static void test_normal_marshal_and_release(void)
726 {
727 HRESULT hr;
728 IStream *pStream = NULL;
729
730 cLocks = 0;
731 external_connections = 0;
732
733 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
734 ok_ole_success(hr, CreateStreamOnHGlobal);
735 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
736 ok_ole_success(hr, CoMarshalInterface);
737
738 ok_more_than_one_lock();
739 ok_non_zero_external_conn();
740
741 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
742 hr = CoReleaseMarshalData(pStream);
743 ok_ole_success(hr, CoReleaseMarshalData);
744 IStream_Release(pStream);
745
746 ok_no_locks();
747 ok_zero_external_conn();
748 ok_last_release_closes(TRUE);
749 }
750
751 /* tests success case of a same-thread marshal and unmarshal */
test_normal_marshal_and_unmarshal(void)752 static void test_normal_marshal_and_unmarshal(void)
753 {
754 HRESULT hr;
755 IStream *pStream = NULL;
756 IUnknown *pProxy = NULL;
757
758 cLocks = 0;
759 external_connections = 0;
760
761 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
762 ok_ole_success(hr, CreateStreamOnHGlobal);
763 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
764 ok_ole_success(hr, CoMarshalInterface);
765
766 ok_more_than_one_lock();
767 ok_non_zero_external_conn();
768
769 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
770 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
771 ok_ole_success(hr, CoUnmarshalInterface);
772 IStream_Release(pStream);
773
774 ok_more_than_one_lock();
775 ok_zero_external_conn();
776 ok_last_release_closes(FALSE);
777
778 IUnknown_Release(pProxy);
779
780 ok_no_locks();
781 }
782
783 /* tests failure case of unmarshaling a freed object */
test_marshal_and_unmarshal_invalid(void)784 static void test_marshal_and_unmarshal_invalid(void)
785 {
786 HRESULT hr;
787 IStream *pStream = NULL;
788 IClassFactory *pProxy = NULL;
789 DWORD tid;
790 void * dummy;
791 HANDLE thread;
792
793 cLocks = 0;
794 external_connections = 0;
795
796 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
797 ok_ole_success(hr, CreateStreamOnHGlobal);
798 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
799
800 ok_more_than_one_lock();
801 ok_non_zero_external_conn();
802
803 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
804 hr = CoReleaseMarshalData(pStream);
805 ok_ole_success(hr, CoReleaseMarshalData);
806
807 ok_no_locks();
808 ok_zero_external_conn();
809 ok_last_release_closes(TRUE);
810
811 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
812 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
813 todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
814
815 ok_no_locks();
816
817 if (pProxy)
818 {
819 hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, &dummy);
820 ok(hr == RPC_E_DISCONNECTED, "Remote call should have returned RPC_E_DISCONNECTED, instead of 0x%08x\n", hr);
821
822 IClassFactory_Release(pProxy);
823 }
824
825 IStream_Release(pStream);
826
827 end_host_object(tid, thread);
828 }
829
test_same_apartment_unmarshal_failure(void)830 static void test_same_apartment_unmarshal_failure(void)
831 {
832 HRESULT hr;
833 IStream *pStream;
834 IUnknown *pProxy;
835 static const LARGE_INTEGER llZero;
836
837 cLocks = 0;
838 external_connections = 0;
839
840 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
841 ok_ole_success(hr, CreateStreamOnHGlobal);
842
843 hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
844 ok_ole_success(hr, CoMarshalInterface);
845
846 ok_more_than_one_lock();
847 ok_non_zero_external_conn();
848
849 hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
850 ok_ole_success(hr, IStream_Seek);
851
852 hr = CoUnmarshalInterface(pStream, &IID_IParseDisplayName, (void **)&pProxy);
853 ok(hr == E_NOINTERFACE, "CoUnmarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
854
855 ok_no_locks();
856 ok_zero_external_conn();
857 ok_last_release_closes(FALSE);
858
859 IStream_Release(pStream);
860 }
861
862 /* tests success case of an interthread marshal */
test_interthread_marshal_and_unmarshal(void)863 static void test_interthread_marshal_and_unmarshal(void)
864 {
865 HRESULT hr;
866 IStream *pStream = NULL;
867 IUnknown *pProxy = NULL;
868 DWORD tid;
869 HANDLE thread;
870
871 cLocks = 0;
872 external_connections = 0;
873
874 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
875 ok_ole_success(hr, CreateStreamOnHGlobal);
876 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
877
878 ok_more_than_one_lock();
879 ok_non_zero_external_conn();
880
881 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
882 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
883 ok_ole_success(hr, CoUnmarshalInterface);
884 IStream_Release(pStream);
885
886 ok_more_than_one_lock();
887 ok_non_zero_external_conn();
888
889 IUnknown_Release(pProxy);
890
891 ok_no_locks();
892 ok_zero_external_conn();
893 ok_last_release_closes(TRUE);
894
895 end_host_object(tid, thread);
896 }
897
898 /* the number of external references that Wine's proxy manager normally gives
899 * out, so we can test the border case of running out of references */
900 #define NORMALEXTREFS 5
901
902 /* tests success case of an interthread marshal and then marshaling the proxy */
test_proxy_marshal_and_unmarshal(void)903 static void test_proxy_marshal_and_unmarshal(void)
904 {
905 HRESULT hr;
906 IStream *pStream = NULL;
907 IUnknown *pProxy = NULL;
908 IUnknown *pProxy2 = NULL;
909 DWORD tid;
910 HANDLE thread;
911 int i;
912
913 cLocks = 0;
914 external_connections = 0;
915
916 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
917 ok_ole_success(hr, CreateStreamOnHGlobal);
918 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
919
920 ok_more_than_one_lock();
921 ok_non_zero_external_conn();
922
923 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
924 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
925 ok_ole_success(hr, CoUnmarshalInterface);
926
927 ok_more_than_one_lock();
928
929 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
930 /* marshal the proxy */
931 hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
932 ok_ole_success(hr, CoMarshalInterface);
933
934 ok_more_than_one_lock();
935
936 /* marshal 5 more times to exhaust the normal external references of 5 */
937 for (i = 0; i < NORMALEXTREFS; i++)
938 {
939 hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
940 ok_ole_success(hr, CoMarshalInterface);
941 }
942
943 ok_more_than_one_lock();
944
945 /* release the original proxy to test that we successfully keep the
946 * original object alive */
947 IUnknown_Release(pProxy);
948
949 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
950 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
951 ok_ole_success(hr, CoUnmarshalInterface);
952
953 ok_more_than_one_lock();
954 ok_non_zero_external_conn();
955
956 IUnknown_Release(pProxy2);
957
958 /* unmarshal all of the proxies to check that the object stub still exists */
959 for (i = 0; i < NORMALEXTREFS; i++)
960 {
961 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
962 ok_ole_success(hr, CoUnmarshalInterface);
963
964 IUnknown_Release(pProxy2);
965 }
966
967 ok_no_locks();
968 ok_zero_external_conn();
969 ok_last_release_closes(TRUE);
970
971 IStream_Release(pStream);
972
973 end_host_object(tid, thread);
974 }
975
976 /* tests success case of an interthread marshal and then marshaling the proxy
977 * using an iid that hasn't previously been unmarshaled */
test_proxy_marshal_and_unmarshal2(void)978 static void test_proxy_marshal_and_unmarshal2(void)
979 {
980 HRESULT hr;
981 IStream *pStream = NULL;
982 IUnknown *pProxy = NULL;
983 IUnknown *pProxy2 = NULL;
984 DWORD tid;
985 HANDLE thread;
986
987 cLocks = 0;
988 external_connections = 0;
989
990 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
991 ok_ole_success(hr, CreateStreamOnHGlobal);
992 tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
993
994 ok_more_than_one_lock();
995 ok_non_zero_external_conn();
996
997 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
998 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
999 ok_ole_success(hr, CoUnmarshalInterface);
1000
1001 ok_more_than_one_lock();
1002
1003 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1004 /* marshal the proxy */
1005 hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1006 ok_ole_success(hr, CoMarshalInterface);
1007
1008 ok_more_than_one_lock();
1009
1010 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1011 /* unmarshal the second proxy to the object */
1012 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1013 ok_ole_success(hr, CoUnmarshalInterface);
1014 IStream_Release(pStream);
1015
1016 /* now the proxies should be as follows:
1017 * pProxy -> &Test_ClassFactory
1018 * pProxy2 -> &Test_ClassFactory
1019 * they should NOT be as follows:
1020 * pProxy -> &Test_ClassFactory
1021 * pProxy2 -> pProxy
1022 * the above can only really be tested by looking in +ole traces
1023 */
1024
1025 ok_more_than_one_lock();
1026
1027 IUnknown_Release(pProxy);
1028
1029 ok_more_than_one_lock();
1030 ok_non_zero_external_conn();
1031
1032 IUnknown_Release(pProxy2);
1033
1034 ok_no_locks();
1035 ok_zero_external_conn();
1036 ok_last_release_closes(TRUE);
1037
1038 end_host_object(tid, thread);
1039 }
1040
1041 /* tests success case of an interthread marshal and then table-weak-marshaling the proxy */
test_proxy_marshal_and_unmarshal_weak(void)1042 static void test_proxy_marshal_and_unmarshal_weak(void)
1043 {
1044 HRESULT hr;
1045 IStream *pStream = NULL;
1046 IUnknown *pProxy = NULL;
1047 IUnknown *pProxy2 = NULL;
1048 DWORD tid;
1049 HANDLE thread;
1050
1051 cLocks = 0;
1052 external_connections = 0;
1053
1054 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1055 ok_ole_success(hr, CreateStreamOnHGlobal);
1056 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1057
1058 ok_more_than_one_lock();
1059 ok_non_zero_external_conn();
1060
1061 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1062 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1063 ok_ole_success(hr, CoUnmarshalInterface);
1064
1065 ok_more_than_one_lock();
1066 ok_non_zero_external_conn();
1067
1068 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1069 /* marshal the proxy */
1070 hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
1071 ok_ole_success(hr, CoMarshalInterface);
1072
1073 ok_more_than_one_lock();
1074 ok_non_zero_external_conn();
1075
1076 /* release the original proxy to test that we successfully keep the
1077 * original object alive */
1078 IUnknown_Release(pProxy);
1079
1080 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1081 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1082 todo_wine
1083 ok(hr == CO_E_OBJNOTREG, "CoUnmarshalInterface should return CO_E_OBJNOTREG instead of 0x%08x\n", hr);
1084
1085 ok_no_locks();
1086 ok_zero_external_conn();
1087 ok_last_release_closes(TRUE);
1088
1089 IStream_Release(pStream);
1090
1091 end_host_object(tid, thread);
1092 }
1093
1094 /* tests success case of an interthread marshal and then table-strong-marshaling the proxy */
test_proxy_marshal_and_unmarshal_strong(void)1095 static void test_proxy_marshal_and_unmarshal_strong(void)
1096 {
1097 HRESULT hr;
1098 IStream *pStream = NULL;
1099 IUnknown *pProxy = NULL;
1100 IUnknown *pProxy2 = NULL;
1101 DWORD tid;
1102 HANDLE thread;
1103
1104 cLocks = 0;
1105 external_connections = 0;
1106
1107 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1108 ok_ole_success(hr, CreateStreamOnHGlobal);
1109 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1110
1111 ok_more_than_one_lock();
1112 ok_non_zero_external_conn();
1113
1114 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1115 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1116 ok_ole_success(hr, CoUnmarshalInterface);
1117
1118 ok_more_than_one_lock();
1119 ok_non_zero_external_conn();
1120
1121 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1122 /* marshal the proxy */
1123 hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG);
1124 ok(hr == S_OK /* WinNT */ || hr == E_INVALIDARG /* Win9x */,
1125 "CoMarshalInterface should have return S_OK or E_INVALIDARG instead of 0x%08x\n", hr);
1126 if (FAILED(hr))
1127 {
1128 IUnknown_Release(pProxy);
1129 goto end;
1130 }
1131
1132 ok_more_than_one_lock();
1133 ok_non_zero_external_conn();
1134
1135 /* release the original proxy to test that we successfully keep the
1136 * original object alive */
1137 IUnknown_Release(pProxy);
1138
1139 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1140 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1141 ok_ole_success(hr, CoUnmarshalInterface);
1142
1143 ok_more_than_one_lock();
1144 ok_non_zero_external_conn();
1145
1146 IUnknown_Release(pProxy2);
1147
1148 ok_more_than_one_lock();
1149 ok_non_zero_external_conn();
1150
1151 end:
1152 IStream_Release(pStream);
1153
1154 end_host_object(tid, thread);
1155
1156 ok_no_locks();
1157 todo_wine {
1158 ok_zero_external_conn();
1159 ok_last_release_closes(FALSE);
1160 }
1161 }
1162
1163 /* tests that stubs are released when the containing apartment is destroyed */
test_marshal_stub_apartment_shutdown(void)1164 static void test_marshal_stub_apartment_shutdown(void)
1165 {
1166 HRESULT hr;
1167 IStream *pStream = NULL;
1168 IUnknown *pProxy = NULL;
1169 DWORD tid;
1170 HANDLE thread;
1171
1172 cLocks = 0;
1173 external_connections = 0;
1174
1175 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1176 ok_ole_success(hr, CreateStreamOnHGlobal);
1177 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1178
1179 ok_more_than_one_lock();
1180 ok_non_zero_external_conn();
1181
1182 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1183 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1184 ok_ole_success(hr, CoUnmarshalInterface);
1185 IStream_Release(pStream);
1186
1187 ok_more_than_one_lock();
1188 ok_non_zero_external_conn();
1189
1190 end_host_object(tid, thread);
1191
1192 ok_no_locks();
1193 todo_wine {
1194 ok_zero_external_conn();
1195 ok_last_release_closes(FALSE);
1196 }
1197
1198 IUnknown_Release(pProxy);
1199
1200 ok_no_locks();
1201 }
1202
1203 /* tests that proxies are released when the containing apartment is destroyed */
test_marshal_proxy_apartment_shutdown(void)1204 static void test_marshal_proxy_apartment_shutdown(void)
1205 {
1206 HRESULT hr;
1207 IStream *pStream = NULL;
1208 IClassFactory *proxy;
1209 IUnknown *unk;
1210 ULONG ref;
1211 DWORD tid;
1212 HANDLE thread;
1213
1214 cLocks = 0;
1215 external_connections = 0;
1216
1217 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1218 ok_ole_success(hr, CreateStreamOnHGlobal);
1219 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1220
1221 ok_more_than_one_lock();
1222 ok_non_zero_external_conn();
1223
1224 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1225 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1226 ok_ole_success(hr, CoUnmarshalInterface);
1227 IStream_Release(pStream);
1228
1229 ok_more_than_one_lock();
1230 ok_non_zero_external_conn();
1231
1232 CoUninitialize();
1233
1234 ok_no_locks();
1235 ok_zero_external_conn();
1236 ok_last_release_closes(TRUE);
1237
1238 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&unk);
1239 ok(hr == CO_E_OBJNOTCONNECTED, "got %#x\n", hr);
1240
1241 ref = IClassFactory_Release(proxy);
1242 ok(!ref, "got %d refs\n", ref);
1243
1244 ok_no_locks();
1245
1246 end_host_object(tid, thread);
1247
1248 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1249 }
1250
1251 /* tests that proxies are released when the containing mta apartment is destroyed */
test_marshal_proxy_mta_apartment_shutdown(void)1252 static void test_marshal_proxy_mta_apartment_shutdown(void)
1253 {
1254 HRESULT hr;
1255 IStream *pStream = NULL;
1256 IUnknown *pProxy = NULL;
1257 DWORD tid;
1258 HANDLE thread;
1259
1260 CoUninitialize();
1261 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1262
1263 cLocks = 0;
1264 external_connections = 0;
1265
1266 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1267 ok_ole_success(hr, CreateStreamOnHGlobal);
1268 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1269
1270 ok_more_than_one_lock();
1271 ok_non_zero_external_conn();
1272
1273 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1274 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1275 ok_ole_success(hr, CoUnmarshalInterface);
1276 IStream_Release(pStream);
1277
1278 ok_more_than_one_lock();
1279 ok_non_zero_external_conn();
1280
1281 CoUninitialize();
1282
1283 ok_no_locks();
1284 ok_zero_external_conn();
1285 ok_last_release_closes(TRUE);
1286
1287 IUnknown_Release(pProxy);
1288
1289 ok_no_locks();
1290
1291 end_host_object(tid, thread);
1292
1293 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1294 }
1295
test_marshal_channel_buffer(void)1296 static void test_marshal_channel_buffer(void)
1297 {
1298 DWORD registration_key;
1299 IUnknown *proxy = NULL;
1300 IOleWindow *ole_window;
1301 HWND hwnd;
1302 CLSID clsid;
1303 DWORD tid;
1304 HANDLE thread;
1305 HRESULT hr;
1306
1307 struct host_object_data object_data = { NULL, &IID_IOleClientSite, (IUnknown*)&Test_OleClientSite,
1308 MSHLFLAGS_NORMAL, NULL, (IUnknown*)&PSFactoryBuffer,
1309 &CLSID_WineTestPSFactoryBuffer };
1310
1311 cLocks = 0;
1312 external_connections = 0;
1313
1314 hr = CoGetPSClsid(&IID_IOleWindow, &clsid);
1315 ok_ole_success(hr, "CoGetPSClsid");
1316
1317 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer,
1318 (void **)&ps_factory_buffer);
1319 ok_ole_success(hr, "CoGetClassObject");
1320
1321 hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
1322 ok_ole_success(hr, CreateStreamOnHGlobal);
1323 tid = start_host_object2(&object_data, &thread);
1324
1325 IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
1326 hr = CoUnmarshalInterface(object_data.stream, &IID_IUnknown, (void **)&proxy);
1327 ok_ole_success(hr, CoUnmarshalInterface);
1328 IStream_Release(object_data.stream);
1329
1330 hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
1331 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key);
1332 ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
1333
1334 hr = CoRegisterPSClsid(&IID_IOleWindow, &CLSID_WineTestPSFactoryBuffer);
1335 ok(hr == S_OK, "CoRegisterPSClsid failed: %08x\n", hr);
1336
1337 SET_EXPECT(CreateStub);
1338 SET_EXPECT(CreateProxy);
1339 hr = IUnknown_QueryInterface(proxy, &IID_IOleWindow, (void**)&ole_window);
1340 ok(hr == S_OK, "Could not get IOleWindow iface: %08x\n", hr);
1341 CHECK_CALLED(CreateStub);
1342 CHECK_CALLED(CreateProxy);
1343
1344 SET_EXPECT(Invoke);
1345 SET_EXPECT(GetWindow);
1346 hr = IOleWindow_GetWindow(ole_window, &hwnd);
1347 ok(hr == S_OK, "GetWindow failed: %08x\n", hr);
1348 ok((DWORD)(DWORD_PTR)hwnd == 0xdeadbeef, "hwnd = %p\n", hwnd);
1349 CHECK_CALLED(Invoke);
1350 CHECK_CALLED(GetWindow);
1351
1352 IOleWindow_Release(ole_window);
1353
1354 SET_EXPECT(Disconnect);
1355 IUnknown_Release(proxy);
1356 todo_wine
1357 CHECK_CALLED(Disconnect);
1358
1359 hr = CoRevokeClassObject(registration_key);
1360 ok(hr == S_OK, "CoRevokeClassObject failed: %08x\n", hr);
1361
1362 end_host_object(tid, thread);
1363 }
1364
1365 static const CLSID *unmarshal_class;
1366 DEFINE_EXPECT(CustomMarshal_GetUnmarshalClass);
1367 DEFINE_EXPECT(CustomMarshal_GetMarshalSizeMax);
1368 DEFINE_EXPECT(CustomMarshal_MarshalInterface);
1369
CustomMarshal_QueryInterface(IMarshal * iface,REFIID riid,void ** ppv)1370 static HRESULT WINAPI CustomMarshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppv)
1371 {
1372 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal)) {
1373 *ppv = iface;
1374 }
1375 else
1376 {
1377 *ppv = NULL;
1378 return E_NOINTERFACE;
1379 }
1380 IUnknown_AddRef((IUnknown*)*ppv);
1381 return S_OK;
1382 }
1383
CustomMarshal_AddRef(IMarshal * iface)1384 static ULONG WINAPI CustomMarshal_AddRef(IMarshal *iface)
1385 {
1386 return 2;
1387 }
1388
CustomMarshal_Release(IMarshal * iface)1389 static ULONG WINAPI CustomMarshal_Release(IMarshal *iface)
1390 {
1391 return 1;
1392 }
1393
CustomMarshal_GetUnmarshalClass(IMarshal * iface,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags,CLSID * clsid)1394 static HRESULT WINAPI CustomMarshal_GetUnmarshalClass(IMarshal *iface, REFIID riid,
1395 void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
1396 {
1397 CHECK_EXPECT(CustomMarshal_GetUnmarshalClass);
1398 *clsid = *unmarshal_class;
1399 return S_OK;
1400 }
1401
CustomMarshal_GetMarshalSizeMax(IMarshal * iface,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags,DWORD * size)1402 static HRESULT WINAPI CustomMarshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid,
1403 void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *size)
1404 {
1405 CHECK_EXPECT(CustomMarshal_GetMarshalSizeMax);
1406 ok(size != NULL, "size = NULL\n");
1407
1408 *size = 0;
1409 return S_OK;
1410 }
1411
CustomMarshal_MarshalInterface(IMarshal * iface,IStream * stream,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags)1412 static HRESULT WINAPI CustomMarshal_MarshalInterface(IMarshal *iface, IStream *stream,
1413 REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
1414 {
1415 IMarshal *std_marshal;
1416 STATSTG stat;
1417 HRESULT hr;
1418
1419 CHECK_EXPECT(CustomMarshal_MarshalInterface);
1420
1421 if(unmarshal_class != &CLSID_StdMarshal)
1422 return S_OK;
1423
1424 hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT);
1425 ok_ole_success(hr, IStream_Stat);
1426 ok(U(stat.cbSize).LowPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).LowPart);
1427 ok(U(stat.cbSize).HighPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).HighPart);
1428
1429 hr = CoGetStandardMarshal(riid, (IUnknown*)iface,
1430 dwDestContext, NULL, mshlflags, &std_marshal);
1431 ok_ole_success(hr, CoGetStandardMarshal);
1432 hr = IMarshal_MarshalInterface(std_marshal, stream, riid, pv,
1433 dwDestContext, pvDestContext, mshlflags);
1434 ok_ole_success(hr, IMarshal_MarshalInterface);
1435 IMarshal_Release(std_marshal);
1436
1437 return S_OK;
1438 }
1439
CustomMarshal_UnmarshalInterface(IMarshal * iface,IStream * stream,REFIID riid,void ** ppv)1440 static HRESULT WINAPI CustomMarshal_UnmarshalInterface(IMarshal *iface,
1441 IStream *stream, REFIID riid, void **ppv)
1442 {
1443 ok(0, "unexpected call\n");
1444 return E_NOTIMPL;
1445 }
1446
CustomMarshal_ReleaseMarshalData(IMarshal * iface,IStream * stream)1447 static HRESULT WINAPI CustomMarshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
1448 {
1449 ok(0, "unexpected call\n");
1450 return E_NOTIMPL;
1451 }
1452
CustomMarshal_DisconnectObject(IMarshal * iface,DWORD res)1453 static HRESULT WINAPI CustomMarshal_DisconnectObject(IMarshal *iface, DWORD res)
1454 {
1455 ok(0, "unexpected call\n");
1456 return E_NOTIMPL;
1457 }
1458
1459 static IMarshalVtbl CustomMarshalVtbl =
1460 {
1461 CustomMarshal_QueryInterface,
1462 CustomMarshal_AddRef,
1463 CustomMarshal_Release,
1464 CustomMarshal_GetUnmarshalClass,
1465 CustomMarshal_GetMarshalSizeMax,
1466 CustomMarshal_MarshalInterface,
1467 CustomMarshal_UnmarshalInterface,
1468 CustomMarshal_ReleaseMarshalData,
1469 CustomMarshal_DisconnectObject
1470 };
1471
1472 static IMarshal CustomMarshal = { &CustomMarshalVtbl };
1473
test_StdMarshal_custom_marshaling(void)1474 static void test_StdMarshal_custom_marshaling(void)
1475 {
1476 IStream *stream;
1477 IUnknown *unk;
1478 DWORD size;
1479 HRESULT hr;
1480
1481 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1482 ok_ole_success(hr, CreateStreamOnHGlobal);
1483
1484 unmarshal_class = &CLSID_StdMarshal;
1485 SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1486 SET_EXPECT(CustomMarshal_MarshalInterface);
1487 hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1488 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1489 ok_ole_success(hr, CoMarshalInterface);
1490 CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1491 CHECK_CALLED(CustomMarshal_MarshalInterface);
1492
1493 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1494 ok_ole_success(hr, IStream_Seek);
1495 hr = CoUnmarshalInterface(stream, &IID_IUnknown, (void**)&unk);
1496 ok_ole_success(hr, CoUnmarshalInterface);
1497 ok(unk == (IUnknown*)&CustomMarshal, "unk != &CustomMarshal\n");
1498 IUnknown_Release(unk);
1499 IStream_Release(stream);
1500
1501 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1502 ok_ole_success(hr, CreateStreamOnHGlobal);
1503
1504 SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1505 SET_EXPECT(CustomMarshal_MarshalInterface);
1506 hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1507 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1508 ok_ole_success(hr, CoMarshalInterface);
1509 CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1510 CHECK_CALLED(CustomMarshal_MarshalInterface);
1511
1512 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1513 ok_ole_success(hr, IStream_Seek);
1514 hr = CoReleaseMarshalData(stream);
1515 ok_ole_success(hr, CoReleaseMarshalData);
1516 IStream_Release(stream);
1517
1518 SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1519 hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1520 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1521 ok_ole_success(hr, CoGetMarshalSizeMax);
1522 CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1523 ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1524 }
1525
test_DfMarshal_custom_marshaling(void)1526 static void test_DfMarshal_custom_marshaling(void)
1527 {
1528 DWORD size, read;
1529 IStream *stream;
1530 OBJREF objref;
1531 HRESULT hr;
1532
1533 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1534 ok_ole_success(hr, CreateStreamOnHGlobal);
1535
1536 unmarshal_class = &CLSID_DfMarshal;
1537 SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1538 SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1539 SET_EXPECT(CustomMarshal_MarshalInterface);
1540 hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1541 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1542 ok_ole_success(hr, CoMarshalInterface);
1543 CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1544 CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1545 CHECK_CALLED(CustomMarshal_MarshalInterface);
1546
1547 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1548 ok_ole_success(hr, IStream_Seek);
1549 size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData);
1550 hr = IStream_Read(stream, &objref, size, &read);
1551 ok_ole_success(hr, IStream_Read);
1552 ok(read == size, "read = %d, expected %d\n", read, size);
1553 ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n",
1554 objref.signature);
1555 ok(objref.flags == OBJREF_CUSTOM, "objref.flags = %x\n", objref.flags);
1556 ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n",
1557 wine_dbgstr_guid(&objref.iid));
1558 ok(IsEqualIID(&objref.u_objref.u_custom.clsid, &CLSID_DfMarshal),
1559 "custom.clsid = %s\n", wine_dbgstr_guid(&objref.u_objref.u_custom.clsid));
1560 ok(!objref.u_objref.u_custom.cbExtension, "custom.cbExtension = %d\n",
1561 objref.u_objref.u_custom.cbExtension);
1562 ok(!objref.u_objref.u_custom.size, "custom.size = %d\n",
1563 objref.u_objref.u_custom.size);
1564
1565 IStream_Release(stream);
1566
1567 SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1568 hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1569 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1570 ok_ole_success(hr, CoGetMarshalSizeMax);
1571 CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1572 ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1573 }
1574
test_CoGetStandardMarshal(void)1575 static void test_CoGetStandardMarshal(void)
1576 {
1577 DUALSTRINGARRAY *dualstringarr;
1578 STDOBJREF *stdobjref;
1579 OBJREF objref;
1580 IMarshal *marshal;
1581 DWORD size, read;
1582 IStream *stream;
1583 IUnknown *unk;
1584 CLSID clsid;
1585 HRESULT hr;
1586
1587 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1588 ok_ole_success(hr, CreateStreamOnHGlobal);
1589
1590 hr = CoGetStandardMarshal(&IID_IUnknown, &Test_Unknown,
1591 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &marshal);
1592 ok_ole_success(hr, CoGetStandardMarshal);
1593
1594 hr = IMarshal_GetUnmarshalClass(marshal, &IID_IUnknown, &Test_Unknown,
1595 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid);
1596 ok_ole_success(hr, IMarshal_GetUnmarshalClass);
1597 ok(IsEqualGUID(&clsid, &CLSID_StdMarshal), "clsid = %s\n", wine_dbgstr_guid(&clsid));
1598
1599 hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IUnknown, &Test_Unknown,
1600 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &size);
1601 ok_ole_success(hr, IMarshal_GetMarshalSizeMax);
1602 hr = CoGetMarshalSizeMax(&read, &IID_IUnknown, &Test_Unknown,
1603 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1604 ok_ole_success(hr, CoGetMarshalSizeMax);
1605 ok(size == read, "IMarshal_GetMarshalSizeMax size = %d, expected %d\n", size, read);
1606
1607 hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown,
1608 &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1609 ok_ole_success(hr, IMarshal_MarshalInterface);
1610
1611 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1612 ok_ole_success(hr, IStream_Seek);
1613 size = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray);
1614 hr = IStream_Read(stream, &objref, size, &read);
1615 ok_ole_success(hr, IStream_Read);
1616 ok(read == size, "read = %d, expected %d\n", read, size);
1617 ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n",
1618 objref.signature);
1619 ok(objref.flags == OBJREF_STANDARD, "objref.flags = %x\n", objref.flags);
1620 ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n",
1621 wine_dbgstr_guid(&objref.iid));
1622 stdobjref = &objref.u_objref.u_standard.std;
1623 ok(stdobjref->flags == 0, "stdobjref.flags = %d\n", stdobjref->flags);
1624 ok(stdobjref->cPublicRefs == 5, "stdobjref.cPublicRefs = %d\n",
1625 stdobjref->cPublicRefs);
1626 dualstringarr = &objref.u_objref.u_standard.saResAddr;
1627 ok(dualstringarr->wNumEntries == 0, "dualstringarr.wNumEntries = %d\n",
1628 dualstringarr->wNumEntries);
1629 ok(dualstringarr->wSecurityOffset == 0, "dualstringarr.wSecurityOffset = %d\n",
1630 dualstringarr->wSecurityOffset);
1631
1632 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1633 ok_ole_success(hr, IStream_Seek);
1634 hr = IMarshal_UnmarshalInterface(marshal, stream, &IID_IUnknown, (void**)&unk);
1635 ok_ole_success(hr, IMarshal_UnmarshalInterface);
1636 IUnknown_Release(unk);
1637
1638 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1639 ok_ole_success(hr, IStream_Seek);
1640 hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown,
1641 &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1642 ok_ole_success(hr, IMarshal_MarshalInterface);
1643
1644 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1645 ok_ole_success(hr, IStream_Seek);
1646 hr = IMarshal_ReleaseMarshalData(marshal, stream);
1647 ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1648 IStream_Release(stream);
1649
1650 IMarshal_Release(marshal);
1651 }
1652 struct ncu_params
1653 {
1654 LPSTREAM stream;
1655 HANDLE marshal_event;
1656 HANDLE unmarshal_event;
1657 };
1658
1659 /* helper for test_no_couninitialize_server */
no_couninitialize_server_proc(LPVOID p)1660 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
1661 {
1662 struct ncu_params *ncu_params = p;
1663 HRESULT hr;
1664
1665 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1666
1667 hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1668 ok_ole_success(hr, CoMarshalInterface);
1669
1670 SetEvent(ncu_params->marshal_event);
1671
1672 ok( !WaitForSingleObject(ncu_params->unmarshal_event, 10000), "wait timed out\n" );
1673
1674 /* die without calling CoUninitialize */
1675
1676 return 0;
1677 }
1678
1679 /* tests apartment that an apartment with a stub is released without deadlock
1680 * if the owning thread exits */
test_no_couninitialize_server(void)1681 static void test_no_couninitialize_server(void)
1682 {
1683 HRESULT hr;
1684 IStream *pStream = NULL;
1685 IUnknown *pProxy = NULL;
1686 DWORD tid;
1687 HANDLE thread;
1688 struct ncu_params ncu_params;
1689
1690 cLocks = 0;
1691 external_connections = 0;
1692
1693 ncu_params.marshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1694 ncu_params.unmarshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1695
1696 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1697 ok_ole_success(hr, CreateStreamOnHGlobal);
1698 ncu_params.stream = pStream;
1699
1700 thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
1701
1702 ok( !WaitForSingleObject(ncu_params.marshal_event, 10000), "wait timed out\n" );
1703 ok_more_than_one_lock();
1704 ok_non_zero_external_conn();
1705
1706 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1707 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1708 ok_ole_success(hr, CoUnmarshalInterface);
1709 IStream_Release(pStream);
1710
1711 ok_more_than_one_lock();
1712 ok_non_zero_external_conn();
1713
1714 SetEvent(ncu_params.unmarshal_event);
1715 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1716
1717 ok_no_locks();
1718 todo_wine {
1719 ok_zero_external_conn();
1720 ok_last_release_closes(FALSE);
1721 }
1722
1723 CloseHandle(thread);
1724 CloseHandle(ncu_params.marshal_event);
1725 CloseHandle(ncu_params.unmarshal_event);
1726
1727 IUnknown_Release(pProxy);
1728
1729 ok_no_locks();
1730 }
1731
1732 /* STA -> STA call during DLL_THREAD_DETACH */
no_couninitialize_client_proc(LPVOID p)1733 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
1734 {
1735 struct ncu_params *ncu_params = p;
1736 HRESULT hr;
1737 IUnknown *pProxy = NULL;
1738
1739 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1740
1741 hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
1742 ok_ole_success(hr, CoUnmarshalInterface);
1743 IStream_Release(ncu_params->stream);
1744
1745 ok_more_than_one_lock();
1746
1747 /* die without calling CoUninitialize */
1748
1749 return 0;
1750 }
1751
1752 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
test_no_couninitialize_client(void)1753 static void test_no_couninitialize_client(void)
1754 {
1755 HRESULT hr;
1756 IStream *pStream = NULL;
1757 DWORD tid;
1758 DWORD host_tid;
1759 HANDLE thread;
1760 HANDLE host_thread;
1761 struct ncu_params ncu_params;
1762
1763 cLocks = 0;
1764 external_connections = 0;
1765
1766 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1767 ok_ole_success(hr, CreateStreamOnHGlobal);
1768 ncu_params.stream = pStream;
1769
1770 /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
1771 * always deadlock when called from within DllMain */
1772 host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
1773 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1774
1775 ok_more_than_one_lock();
1776 ok_non_zero_external_conn();
1777
1778 thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
1779
1780 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1781 CloseHandle(thread);
1782
1783 ok_no_locks();
1784 ok_zero_external_conn();
1785 ok_last_release_closes(TRUE);
1786
1787 end_host_object(host_tid, host_thread);
1788 }
1789
1790 static BOOL crash_thread_success;
1791
crash_couninitialize_proc(void * p)1792 static DWORD CALLBACK crash_couninitialize_proc(void *p)
1793 {
1794 IStream *stream;
1795 HRESULT hr;
1796
1797 cLocks = 0;
1798
1799 CoInitialize(NULL);
1800
1801 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1802 ok_ole_success(hr, CreateStreamOnHGlobal);
1803
1804 hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1805 ok_ole_success(hr, CoMarshalInterface);
1806
1807 IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1808
1809 hr = CoReleaseMarshalData(stream);
1810 ok_ole_success(hr, CoReleaseMarshalData);
1811
1812 ok_no_locks();
1813
1814 hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1815 ok_ole_success(hr, CoMarshalInterface);
1816
1817 ok_more_than_one_lock();
1818
1819 trace("CoUninitialize >>>\n");
1820 CoUninitialize();
1821 trace("CoUninitialize <<<\n");
1822
1823 ok_no_locks();
1824
1825 IStream_Release(stream);
1826 crash_thread_success = TRUE;
1827 return 0;
1828 }
1829
test_crash_couninitialize(void)1830 static void test_crash_couninitialize(void)
1831 {
1832 HANDLE thread;
1833 DWORD tid;
1834
1835 if(!GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateActCtxW")) {
1836 win_skip("Skipping crash tests on win2k.\n");
1837 return;
1838 }
1839
1840 crash_thread_success = FALSE;
1841 thread = CreateThread(NULL, 0, crash_couninitialize_proc, NULL, 0, &tid);
1842 ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1843 CloseHandle(thread);
1844 ok(crash_thread_success, "Crash thread failed\n");
1845 }
1846
1847 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
test_tableweak_marshal_and_unmarshal_twice(void)1848 static void test_tableweak_marshal_and_unmarshal_twice(void)
1849 {
1850 HRESULT hr;
1851 IStream *pStream = NULL;
1852 IUnknown *pProxy1 = NULL;
1853 IUnknown *pProxy2 = NULL;
1854 DWORD tid;
1855 HANDLE thread;
1856
1857 cLocks = 0;
1858 external_connections = 0;
1859
1860 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1861 ok_ole_success(hr, CreateStreamOnHGlobal);
1862 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1863
1864 ok_more_than_one_lock();
1865 ok_zero_external_conn();
1866
1867 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1868 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1869 ok_ole_success(hr, CoUnmarshalInterface);
1870
1871 ok_more_than_one_lock();
1872 ok_non_zero_external_conn();
1873
1874 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1875 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1876 ok_ole_success(hr, CoUnmarshalInterface);
1877
1878 ok_more_than_one_lock();
1879
1880 IUnknown_Release(pProxy1);
1881 ok_non_zero_external_conn();
1882 IUnknown_Release(pProxy2);
1883 ok_zero_external_conn();
1884 ok_last_release_closes(TRUE);
1885
1886 /* When IExternalConnection is present COM's lifetime management
1887 * behaviour is altered; the remaining weak ref prevents stub shutdown. */
1888 if (with_external_conn)
1889 {
1890 ok_more_than_one_lock();
1891 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1892 release_host_object(tid, 0);
1893 }
1894
1895 /* Without IExternalConnection this line is shows the difference between weak and strong table marshaling
1896 * weak has cLocks == 0, strong has cLocks > 0. */
1897 ok_no_locks();
1898
1899 IStream_Release(pStream);
1900 end_host_object(tid, thread);
1901 }
1902
1903 /* tests releasing after unmarshaling one object */
test_tableweak_marshal_releasedata1(void)1904 static void test_tableweak_marshal_releasedata1(void)
1905 {
1906 HRESULT hr;
1907 IStream *pStream = NULL;
1908 IUnknown *pProxy1 = NULL;
1909 IUnknown *pProxy2 = NULL;
1910 DWORD tid;
1911 HANDLE thread;
1912
1913 cLocks = 0;
1914 external_connections = 0;
1915
1916 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1917 ok_ole_success(hr, CreateStreamOnHGlobal);
1918 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1919
1920 ok_more_than_one_lock();
1921 ok_zero_external_conn();
1922
1923 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1924 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1925 ok_ole_success(hr, CoUnmarshalInterface);
1926
1927 ok_more_than_one_lock();
1928 ok_non_zero_external_conn();
1929
1930 /* release the remaining reference on the object by calling
1931 * CoReleaseMarshalData in the hosting thread */
1932 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1933 release_host_object(tid, 0);
1934
1935 ok_more_than_one_lock();
1936 ok_non_zero_external_conn();
1937
1938 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1939 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1940 ok_ole_success(hr, CoUnmarshalInterface);
1941 IStream_Release(pStream);
1942
1943 ok_more_than_one_lock();
1944 ok_non_zero_external_conn();
1945
1946 IUnknown_Release(pProxy1);
1947
1948 if (pProxy2)
1949 {
1950 ok_non_zero_external_conn();
1951 IUnknown_Release(pProxy2);
1952 }
1953
1954 /* this line is shows the difference between weak and strong table marshaling:
1955 * weak has cLocks == 0
1956 * strong has cLocks > 0 */
1957 ok_no_locks();
1958 ok_zero_external_conn();
1959 ok_last_release_closes(TRUE);
1960
1961 end_host_object(tid, thread);
1962 }
1963
1964 /* tests releasing after unmarshaling one object */
test_tableweak_marshal_releasedata2(void)1965 static void test_tableweak_marshal_releasedata2(void)
1966 {
1967 HRESULT hr;
1968 IStream *pStream = NULL;
1969 IUnknown *pProxy = NULL;
1970 DWORD tid;
1971 HANDLE thread;
1972
1973 cLocks = 0;
1974 external_connections = 0;
1975
1976 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1977 ok_ole_success(hr, CreateStreamOnHGlobal);
1978 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1979
1980 ok_more_than_one_lock();
1981 ok_zero_external_conn();
1982
1983 /* release the remaining reference on the object by calling
1984 * CoReleaseMarshalData in the hosting thread */
1985 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1986 release_host_object(tid, 0);
1987
1988 ok_no_locks();
1989
1990 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1991 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1992 todo_wine
1993 {
1994 ok(hr == CO_E_OBJNOTREG,
1995 "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08x instead\n",
1996 hr);
1997 }
1998 IStream_Release(pStream);
1999
2000 ok_no_locks();
2001 ok_zero_external_conn();
2002
2003 end_host_object(tid, thread);
2004 }
2005
2006 struct duo_marshal_data
2007 {
2008 MSHLFLAGS marshal_flags1, marshal_flags2;
2009 IStream *pStream1, *pStream2;
2010 HANDLE hReadyEvent;
2011 HANDLE hQuitEvent;
2012 };
2013
duo_marshal_thread_proc(void * p)2014 static DWORD CALLBACK duo_marshal_thread_proc(void *p)
2015 {
2016 HRESULT hr;
2017 struct duo_marshal_data *data = p;
2018 HANDLE hQuitEvent = data->hQuitEvent;
2019 MSG msg;
2020
2021 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2022
2023 hr = CoMarshalInterface(data->pStream1, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags1);
2024 ok_ole_success(hr, "CoMarshalInterface");
2025
2026 hr = CoMarshalInterface(data->pStream2, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags2);
2027 ok_ole_success(hr, "CoMarshalInterface");
2028
2029 /* force the message queue to be created before signaling parent thread */
2030 PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
2031
2032 SetEvent(data->hReadyEvent);
2033
2034 while (WAIT_OBJECT_0 + 1 == MsgWaitForMultipleObjects(1, &hQuitEvent, FALSE, 10000, QS_ALLINPUT))
2035 {
2036 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
2037 {
2038 if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
2039 {
2040 CoReleaseMarshalData(msg.wParam == 1 ? data->pStream1 : data->pStream2);
2041 SetEvent((HANDLE)msg.lParam);
2042 }
2043 else
2044 DispatchMessageA(&msg);
2045 }
2046 }
2047 CloseHandle(hQuitEvent);
2048
2049 CoUninitialize();
2050
2051 return 0;
2052 }
2053
2054 /* tests interaction between table-weak and normal marshalling of an object */
test_tableweak_and_normal_marshal_and_unmarshal(void)2055 static void test_tableweak_and_normal_marshal_and_unmarshal(void)
2056 {
2057 HRESULT hr;
2058 IUnknown *pProxyWeak = NULL;
2059 IUnknown *pProxyNormal = NULL;
2060 DWORD tid;
2061 HANDLE thread;
2062 struct duo_marshal_data data;
2063
2064 cLocks = 0;
2065 external_connections = 0;
2066
2067 data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2068 data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2069 data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2070 data.marshal_flags2 = MSHLFLAGS_NORMAL;
2071 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2072 ok_ole_success(hr, CreateStreamOnHGlobal);
2073 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2074 ok_ole_success(hr, CreateStreamOnHGlobal);
2075
2076 thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2077 ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2078 CloseHandle(data.hReadyEvent);
2079
2080 ok_more_than_one_lock();
2081 ok_non_zero_external_conn();
2082
2083 /* weak */
2084 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2085 hr = CoUnmarshalInterface(data.pStream1, &IID_IClassFactory, (void **)&pProxyWeak);
2086 ok_ole_success(hr, CoUnmarshalInterface);
2087
2088 ok_more_than_one_lock();
2089
2090 /* normal */
2091 IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2092 hr = CoUnmarshalInterface(data.pStream2, &IID_IClassFactory, (void **)&pProxyNormal);
2093 ok_ole_success(hr, CoUnmarshalInterface);
2094
2095 ok_more_than_one_lock();
2096
2097 IUnknown_Release(pProxyNormal);
2098
2099 ok_more_than_one_lock();
2100 ok_non_zero_external_conn();
2101
2102 IUnknown_Release(pProxyWeak);
2103
2104 ok_zero_external_conn();
2105 ok_last_release_closes(TRUE);
2106
2107 /* When IExternalConnection is present COM's lifetime management
2108 * behaviour is altered; the remaining weak ref prevents stub shutdown. */
2109 if (with_external_conn)
2110 {
2111 ok_more_than_one_lock();
2112 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2113 release_host_object(tid, 1);
2114 }
2115 ok_no_locks();
2116
2117 IStream_Release(data.pStream1);
2118 IStream_Release(data.pStream2);
2119
2120 SetEvent(data.hQuitEvent);
2121 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2122 CloseHandle(thread);
2123 }
2124
test_tableweak_and_normal_marshal_and_releasedata(void)2125 static void test_tableweak_and_normal_marshal_and_releasedata(void)
2126 {
2127 HRESULT hr;
2128 DWORD tid;
2129 HANDLE thread;
2130 struct duo_marshal_data data;
2131
2132 cLocks = 0;
2133 external_connections = 0;
2134
2135 data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2136 data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2137 data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2138 data.marshal_flags2 = MSHLFLAGS_NORMAL;
2139 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2140 ok_ole_success(hr, CreateStreamOnHGlobal);
2141 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2142 ok_ole_success(hr, CreateStreamOnHGlobal);
2143
2144 thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2145 ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2146 CloseHandle(data.hReadyEvent);
2147
2148 ok_more_than_one_lock();
2149 ok_non_zero_external_conn();
2150
2151 /* release normal - which in the non-external conn case will free the object despite the weak ref. */
2152 IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2153 release_host_object(tid, 2);
2154
2155 ok_zero_external_conn();
2156 ok_last_release_closes(TRUE);
2157
2158 if (with_external_conn)
2159 {
2160 ok_more_than_one_lock();
2161 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2162 release_host_object(tid, 1);
2163 }
2164
2165 ok_no_locks();
2166
2167 IStream_Release(data.pStream1);
2168 IStream_Release(data.pStream2);
2169
2170 SetEvent(data.hQuitEvent);
2171 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2172 CloseHandle(thread);
2173 }
2174
test_two_tableweak_marshal_and_releasedata(void)2175 static void test_two_tableweak_marshal_and_releasedata(void)
2176 {
2177 HRESULT hr;
2178 DWORD tid;
2179 HANDLE thread;
2180 struct duo_marshal_data data;
2181
2182 cLocks = 0;
2183 external_connections = 0;
2184
2185 data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2186 data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2187 data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2188 data.marshal_flags2 = MSHLFLAGS_TABLEWEAK;
2189 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2190 ok_ole_success(hr, CreateStreamOnHGlobal);
2191 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2192 ok_ole_success(hr, CreateStreamOnHGlobal);
2193
2194 thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2195 ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2196 CloseHandle(data.hReadyEvent);
2197
2198 ok_more_than_one_lock();
2199 ok_zero_external_conn();
2200
2201 /* release one weak ref - the remaining weak ref will keep the obj alive */
2202 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2203 release_host_object(tid, 1);
2204
2205 ok_more_than_one_lock();
2206
2207 IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2208 release_host_object(tid, 2);
2209
2210 ok_no_locks();
2211
2212 IStream_Release(data.pStream1);
2213 IStream_Release(data.pStream2);
2214
2215 SetEvent(data.hQuitEvent);
2216 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2217 CloseHandle(thread);
2218 }
2219
2220 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
test_tablestrong_marshal_and_unmarshal_twice(void)2221 static void test_tablestrong_marshal_and_unmarshal_twice(void)
2222 {
2223 HRESULT hr;
2224 IStream *pStream = NULL;
2225 IUnknown *pProxy1 = NULL;
2226 IUnknown *pProxy2 = NULL;
2227 DWORD tid;
2228 HANDLE thread;
2229
2230 cLocks = 0;
2231 external_connections = 0;
2232
2233 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2234 ok_ole_success(hr, CreateStreamOnHGlobal);
2235 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
2236
2237 ok_more_than_one_lock();
2238 ok_non_zero_external_conn();
2239
2240 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2241 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2242 ok_ole_success(hr, CoUnmarshalInterface);
2243
2244 ok_more_than_one_lock();
2245
2246 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2247 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2248 ok_ole_success(hr, CoUnmarshalInterface);
2249
2250 ok_more_than_one_lock();
2251
2252 if (pProxy1) IUnknown_Release(pProxy1);
2253 if (pProxy2) IUnknown_Release(pProxy2);
2254
2255 /* this line is shows the difference between weak and strong table marshaling:
2256 * weak has cLocks == 0
2257 * strong has cLocks > 0 */
2258 ok_more_than_one_lock();
2259
2260 /* release the remaining reference on the object by calling
2261 * CoReleaseMarshalData in the hosting thread */
2262 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2263 release_host_object(tid, 0);
2264 IStream_Release(pStream);
2265
2266 ok_no_locks();
2267 ok_zero_external_conn();
2268 ok_last_release_closes(TRUE);
2269
2270 end_host_object(tid, thread);
2271 }
2272
2273 /* tests CoLockObjectExternal */
test_lock_object_external(void)2274 static void test_lock_object_external(void)
2275 {
2276 HRESULT hr;
2277 IStream *pStream = NULL;
2278
2279 cLocks = 0;
2280 external_connections = 0;
2281
2282 /* test the stub manager creation aspect of CoLockObjectExternal when the
2283 * object hasn't been marshaled yet */
2284 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2285
2286 ok_more_than_one_lock();
2287 ok_non_zero_external_conn();
2288
2289 CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2290
2291 ok_no_locks();
2292 ok_non_zero_external_conn();
2293 external_connections = 0;
2294
2295 /* test our empty stub manager being handled correctly in
2296 * CoMarshalInterface */
2297 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2298
2299 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2300 ok_ole_success(hr, CreateStreamOnHGlobal);
2301 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2302 ok_ole_success(hr, CoMarshalInterface);
2303
2304 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2305
2306 ok_more_than_one_lock();
2307 ok_non_zero_external_conn();
2308
2309 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2310 hr = CoReleaseMarshalData(pStream);
2311 ok_ole_success(hr, CoReleaseMarshalData);
2312 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2313
2314 ok_more_than_one_lock();
2315 ok_non_zero_external_conn();
2316 ok_last_release_closes(TRUE);
2317
2318 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
2319
2320 ok_more_than_one_lock();
2321 ok_non_zero_external_conn();
2322 ok_last_release_closes(TRUE);
2323
2324 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
2325
2326 ok_no_locks();
2327 ok_zero_external_conn();
2328 ok_last_release_closes(TRUE);
2329
2330 /* test CoLockObjectExternal releases reference to object with
2331 * fLastUnlockReleases as TRUE and there are only strong references on
2332 * the object */
2333 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
2334
2335 ok_more_than_one_lock();
2336 ok_non_zero_external_conn();
2337
2338 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2339
2340 ok_no_locks();
2341 ok_zero_external_conn();
2342 ok_last_release_closes(FALSE);
2343
2344 /* test CoLockObjectExternal doesn't release the last reference to an
2345 * object with fLastUnlockReleases as TRUE and there is a weak reference
2346 * on the object */
2347 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
2348 ok_ole_success(hr, CoMarshalInterface);
2349
2350 ok_more_than_one_lock();
2351 ok_zero_external_conn();
2352
2353 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
2354
2355 ok_more_than_one_lock();
2356 ok_non_zero_external_conn();
2357
2358 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2359
2360 ok_more_than_one_lock();
2361 ok_zero_external_conn();
2362 ok_last_release_closes(FALSE);
2363
2364 CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2365
2366 ok_no_locks();
2367
2368 IStream_Release(pStream);
2369 }
2370
2371 /* tests disconnecting stubs */
test_disconnect_stub(void)2372 static void test_disconnect_stub(void)
2373 {
2374 HRESULT hr;
2375 IStream *pStream = NULL;
2376
2377 cLocks = 0;
2378 external_connections = 0;
2379
2380 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2381 ok_ole_success(hr, CreateStreamOnHGlobal);
2382 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2383 ok_ole_success(hr, CoMarshalInterface);
2384
2385 ok_non_zero_external_conn();
2386
2387 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2388
2389 ok_more_than_one_lock();
2390 ok_non_zero_external_conn();
2391
2392 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2393 hr = CoReleaseMarshalData(pStream);
2394 ok_ole_success(hr, CoReleaseMarshalData);
2395 IStream_Release(pStream);
2396
2397 ok_more_than_one_lock();
2398 ok_non_zero_external_conn();
2399
2400 CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2401
2402 ok_no_locks();
2403 ok_non_zero_external_conn();
2404
2405 hr = CoDisconnectObject(NULL, 0);
2406 ok( hr == E_INVALIDARG, "wrong status %x\n", hr );
2407 }
2408
2409 /* tests failure case of a same-thread marshal and unmarshal twice */
test_normal_marshal_and_unmarshal_twice(void)2410 static void test_normal_marshal_and_unmarshal_twice(void)
2411 {
2412 HRESULT hr;
2413 IStream *pStream = NULL;
2414 IUnknown *pProxy1 = NULL;
2415 IUnknown *pProxy2 = NULL;
2416
2417 cLocks = 0;
2418 external_connections = 0;
2419
2420 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2421 ok_ole_success(hr, CreateStreamOnHGlobal);
2422 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2423 ok_ole_success(hr, CoMarshalInterface);
2424
2425 ok_more_than_one_lock();
2426 ok_non_zero_external_conn();
2427
2428 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2429 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2430 ok_ole_success(hr, CoUnmarshalInterface);
2431
2432 ok_more_than_one_lock();
2433 ok_zero_external_conn();
2434 ok_last_release_closes(FALSE);
2435
2436 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2437 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2438 ok(hr == CO_E_OBJNOTCONNECTED,
2439 "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08x\n", hr);
2440
2441 IStream_Release(pStream);
2442
2443 ok_more_than_one_lock();
2444
2445 IUnknown_Release(pProxy1);
2446
2447 ok_no_locks();
2448 }
2449
2450 /* tests success case of marshaling and unmarshaling an HRESULT */
test_hresult_marshaling(void)2451 static void test_hresult_marshaling(void)
2452 {
2453 HRESULT hr;
2454 HRESULT hr_marshaled = 0;
2455 IStream *pStream = NULL;
2456 static const HRESULT E_DEADBEEF = 0xdeadbeef;
2457
2458 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2459 ok_ole_success(hr, CreateStreamOnHGlobal);
2460
2461 hr = CoMarshalHresult(pStream, E_DEADBEEF);
2462 ok_ole_success(hr, CoMarshalHresult);
2463
2464 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2465 hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
2466 ok_ole_success(hr, IStream_Read);
2467
2468 ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2469
2470 hr_marshaled = 0;
2471 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2472 hr = CoUnmarshalHresult(pStream, &hr_marshaled);
2473 ok_ole_success(hr, CoUnmarshalHresult);
2474
2475 ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2476
2477 IStream_Release(pStream);
2478 }
2479
2480
2481 /* helper for test_proxy_used_in_wrong_thread */
bad_thread_proc(LPVOID p)2482 static DWORD CALLBACK bad_thread_proc(LPVOID p)
2483 {
2484 IClassFactory * cf = p;
2485 HRESULT hr;
2486 IUnknown * proxy = NULL;
2487
2488 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2489 todo_wine
2490 ok(hr == CO_E_NOTINITIALIZED,
2491 "COM should have failed with CO_E_NOTINITIALIZED on using proxy without apartment, but instead returned 0x%08x\n",
2492 hr);
2493
2494 hr = IClassFactory_QueryInterface(cf, &IID_IMultiQI, (LPVOID *)&proxy);
2495 /* Win9x returns S_OK, whilst NT returns RPC_E_WRONG_THREAD */
2496 trace("call to proxy's QueryInterface for local interface without apartment returned 0x%08x\n", hr);
2497 if (SUCCEEDED(hr))
2498 IUnknown_Release(proxy);
2499
2500 hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2501 /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2502 trace("call to proxy's QueryInterface without apartment returned 0x%08x\n", hr);
2503 if (SUCCEEDED(hr))
2504 IUnknown_Release(proxy);
2505
2506 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
2507
2508 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2509 if (proxy) IUnknown_Release(proxy);
2510 ok(hr == RPC_E_WRONG_THREAD,
2511 "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n",
2512 hr);
2513
2514 hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2515 /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2516 trace("call to proxy's QueryInterface from wrong apartment returned 0x%08x\n", hr);
2517
2518 /* now be really bad and release the proxy from the wrong apartment */
2519 IClassFactory_Release(cf);
2520
2521 CoUninitialize();
2522
2523 return 0;
2524 }
2525
2526 /* tests failure case of a using a proxy in the wrong apartment */
test_proxy_used_in_wrong_thread(void)2527 static void test_proxy_used_in_wrong_thread(void)
2528 {
2529 HRESULT hr;
2530 IStream *pStream = NULL;
2531 IUnknown *pProxy = NULL;
2532 DWORD tid, tid2;
2533 HANDLE thread;
2534 HANDLE host_thread;
2535
2536 cLocks = 0;
2537
2538 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2539 ok_ole_success(hr, CreateStreamOnHGlobal);
2540 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
2541
2542 ok_more_than_one_lock();
2543
2544 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2545 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
2546 ok_ole_success(hr, CoUnmarshalInterface);
2547 IStream_Release(pStream);
2548
2549 ok_more_than_one_lock();
2550
2551 /* do a call that will fail, but result in IRemUnknown being used by the proxy */
2552 IUnknown_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream);
2553
2554 /* create a thread that we can misbehave in */
2555 thread = CreateThread(NULL, 0, bad_thread_proc, pProxy, 0, &tid2);
2556
2557 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2558 CloseHandle(thread);
2559
2560 /* do release statement on Win9x that we should have done above */
2561 if (!GetProcAddress(GetModuleHandleA("ole32"), "CoRegisterSurrogateEx"))
2562 IUnknown_Release(pProxy);
2563
2564 ok_no_locks();
2565
2566 end_host_object(tid, host_thread);
2567 }
2568
MessageFilter_QueryInterface(IMessageFilter * iface,REFIID riid,void ** ppvObj)2569 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
2570 {
2571 if (ppvObj == NULL) return E_POINTER;
2572
2573 if (IsEqualGUID(riid, &IID_IUnknown) ||
2574 IsEqualGUID(riid, &IID_IClassFactory))
2575 {
2576 *ppvObj = iface;
2577 IMessageFilter_AddRef(iface);
2578 return S_OK;
2579 }
2580
2581 return E_NOINTERFACE;
2582 }
2583
MessageFilter_AddRef(IMessageFilter * iface)2584 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
2585 {
2586 return 2; /* non-heap object */
2587 }
2588
MessageFilter_Release(IMessageFilter * iface)2589 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
2590 {
2591 return 1; /* non-heap object */
2592 }
2593
MessageFilter_HandleInComingCall(IMessageFilter * iface,DWORD dwCallType,HTASK threadIDCaller,DWORD dwTickCount,LPINTERFACEINFO lpInterfaceInfo)2594 static DWORD WINAPI MessageFilter_HandleInComingCall(
2595 IMessageFilter *iface,
2596 DWORD dwCallType,
2597 HTASK threadIDCaller,
2598 DWORD dwTickCount,
2599 LPINTERFACEINFO lpInterfaceInfo)
2600 {
2601 static int callcount = 0;
2602 DWORD ret;
2603 trace("HandleInComingCall\n");
2604 switch (callcount)
2605 {
2606 case 0:
2607 ret = SERVERCALL_REJECTED;
2608 break;
2609 case 1:
2610 ret = SERVERCALL_RETRYLATER;
2611 break;
2612 default:
2613 ret = SERVERCALL_ISHANDLED;
2614 break;
2615 }
2616 callcount++;
2617 return ret;
2618 }
2619
MessageFilter_RetryRejectedCall(IMessageFilter * iface,HTASK threadIDCallee,DWORD dwTickCount,DWORD dwRejectType)2620 static DWORD WINAPI MessageFilter_RetryRejectedCall(
2621 IMessageFilter *iface,
2622 HTASK threadIDCallee,
2623 DWORD dwTickCount,
2624 DWORD dwRejectType)
2625 {
2626 trace("RetryRejectedCall\n");
2627 return 0;
2628 }
2629
MessageFilter_MessagePending(IMessageFilter * iface,HTASK threadIDCallee,DWORD dwTickCount,DWORD dwPendingType)2630 static DWORD WINAPI MessageFilter_MessagePending(
2631 IMessageFilter *iface,
2632 HTASK threadIDCallee,
2633 DWORD dwTickCount,
2634 DWORD dwPendingType)
2635 {
2636 trace("MessagePending\n");
2637 return PENDINGMSG_WAITNOPROCESS;
2638 }
2639
2640 static const IMessageFilterVtbl MessageFilter_Vtbl =
2641 {
2642 MessageFilter_QueryInterface,
2643 MessageFilter_AddRef,
2644 MessageFilter_Release,
2645 MessageFilter_HandleInComingCall,
2646 MessageFilter_RetryRejectedCall,
2647 MessageFilter_MessagePending
2648 };
2649
2650 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
2651
test_message_filter(void)2652 static void test_message_filter(void)
2653 {
2654 HRESULT hr;
2655 IClassFactory *cf = NULL;
2656 DWORD tid;
2657 IUnknown *proxy = NULL;
2658 IMessageFilter *prev_filter = NULL;
2659 HANDLE thread;
2660
2661 struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
2662 MSHLFLAGS_NORMAL, &MessageFilter };
2663
2664 cLocks = 0;
2665
2666 hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
2667 ok_ole_success(hr, CreateStreamOnHGlobal);
2668 tid = start_host_object2(&object_data, &thread);
2669
2670 ok_more_than_one_lock();
2671
2672 IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
2673 hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
2674 ok_ole_success(hr, CoUnmarshalInterface);
2675 IStream_Release(object_data.stream);
2676
2677 ok_more_than_one_lock();
2678
2679 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2680 ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08x instead\n", hr);
2681 if (proxy) IUnknown_Release(proxy);
2682 proxy = NULL;
2683
2684 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
2685 ok_ole_success(hr, CoRegisterMessageFilter);
2686
2687 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2688 ok_ole_success(hr, IClassFactory_CreateInstance);
2689
2690 IUnknown_Release(proxy);
2691
2692 IClassFactory_Release(cf);
2693
2694 ok_no_locks();
2695
2696 end_host_object(tid, thread);
2697
2698 hr = CoRegisterMessageFilter(prev_filter, NULL);
2699 ok_ole_success(hr, CoRegisterMessageFilter);
2700 }
2701
2702 /* test failure case of trying to unmarshal from bad stream */
test_bad_marshal_stream(void)2703 static void test_bad_marshal_stream(void)
2704 {
2705 HRESULT hr;
2706 IStream *pStream = NULL;
2707
2708 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2709 ok_ole_success(hr, CreateStreamOnHGlobal);
2710 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2711 ok_ole_success(hr, CoMarshalInterface);
2712
2713 ok_more_than_one_lock();
2714
2715 /* try to read beyond end of stream */
2716 hr = CoReleaseMarshalData(pStream);
2717 ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08x instead\n", hr);
2718
2719 /* now release for real */
2720 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2721 hr = CoReleaseMarshalData(pStream);
2722 ok_ole_success(hr, CoReleaseMarshalData);
2723
2724 IStream_Release(pStream);
2725 }
2726
2727 /* tests that proxies implement certain interfaces */
test_proxy_interfaces(void)2728 static void test_proxy_interfaces(void)
2729 {
2730 HRESULT hr;
2731 IStream *pStream = NULL;
2732 IUnknown *pProxy = NULL;
2733 IUnknown *pOtherUnknown = NULL;
2734 DWORD tid;
2735 HANDLE thread;
2736
2737 cLocks = 0;
2738
2739 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2740 ok_ole_success(hr, CreateStreamOnHGlobal);
2741 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2742
2743 ok_more_than_one_lock();
2744
2745 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2746 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
2747 ok_ole_success(hr, CoUnmarshalInterface);
2748 IStream_Release(pStream);
2749
2750 ok_more_than_one_lock();
2751
2752 hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
2753 ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
2754 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2755
2756 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
2757 ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity);
2758 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2759
2760 hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
2761 ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
2762 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2763
2764 hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
2765 ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal);
2766 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2767
2768 /* IMarshal2 is also supported on NT-based systems, but is pretty much
2769 * useless as it has no more methods over IMarshal that it inherits from. */
2770
2771 IUnknown_Release(pProxy);
2772
2773 ok_no_locks();
2774
2775 end_host_object(tid, thread);
2776 }
2777
2778 typedef struct
2779 {
2780 IUnknown IUnknown_iface;
2781 ULONG refs;
2782 } HeapUnknown;
2783
impl_from_IUnknown(IUnknown * iface)2784 static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
2785 {
2786 return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
2787 }
2788
HeapUnknown_QueryInterface(IUnknown * iface,REFIID riid,void ** ppv)2789 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2790 {
2791 if (IsEqualIID(riid, &IID_IUnknown))
2792 {
2793 IUnknown_AddRef(iface);
2794 *ppv = iface;
2795 return S_OK;
2796 }
2797 *ppv = NULL;
2798 return E_NOINTERFACE;
2799 }
2800
HeapUnknown_AddRef(IUnknown * iface)2801 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
2802 {
2803 HeapUnknown *This = impl_from_IUnknown(iface);
2804 return InterlockedIncrement((LONG*)&This->refs);
2805 }
2806
HeapUnknown_Release(IUnknown * iface)2807 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
2808 {
2809 HeapUnknown *This = impl_from_IUnknown(iface);
2810 ULONG refs = InterlockedDecrement((LONG*)&This->refs);
2811 if (!refs) HeapFree(GetProcessHeap(), 0, This);
2812 return refs;
2813 }
2814
2815 static const IUnknownVtbl HeapUnknown_Vtbl =
2816 {
2817 HeapUnknown_QueryInterface,
2818 HeapUnknown_AddRef,
2819 HeapUnknown_Release
2820 };
2821
test_proxybuffer(REFIID riid)2822 static void test_proxybuffer(REFIID riid)
2823 {
2824 HRESULT hr;
2825 IPSFactoryBuffer *psfb;
2826 IRpcProxyBuffer *proxy;
2827 LPVOID lpvtbl;
2828 ULONG refs;
2829 CLSID clsid;
2830 HeapUnknown *pUnkOuter = HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
2831
2832 pUnkOuter->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
2833 pUnkOuter->refs = 1;
2834
2835 hr = CoGetPSClsid(riid, &clsid);
2836 ok_ole_success(hr, CoGetPSClsid);
2837
2838 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2839 ok_ole_success(hr, CoGetClassObject);
2840
2841 hr = IPSFactoryBuffer_CreateProxy(psfb, &pUnkOuter->IUnknown_iface, riid, &proxy, &lpvtbl);
2842 ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
2843 ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
2844
2845 /* release our reference to the outer unknown object - the PS factory
2846 * buffer will have AddRef's it in the CreateProxy call */
2847 refs = IUnknown_Release(&pUnkOuter->IUnknown_iface);
2848 ok(refs == 1, "Ref count of outer unknown should have been 1 instead of %d\n", refs);
2849
2850 /* Not checking return, unreliable on native. Maybe it leaks references? */
2851 IPSFactoryBuffer_Release(psfb);
2852
2853 refs = IUnknown_Release((IUnknown *)lpvtbl);
2854 ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2855
2856 refs = IRpcProxyBuffer_Release(proxy);
2857 ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2858 }
2859
test_stubbuffer(REFIID riid)2860 static void test_stubbuffer(REFIID riid)
2861 {
2862 HRESULT hr;
2863 IPSFactoryBuffer *psfb;
2864 IRpcStubBuffer *stub;
2865 ULONG refs;
2866 CLSID clsid;
2867
2868 cLocks = 0;
2869
2870 hr = CoGetPSClsid(riid, &clsid);
2871 ok_ole_success(hr, CoGetPSClsid);
2872
2873 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2874 ok_ole_success(hr, CoGetClassObject);
2875
2876 hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
2877 ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
2878
2879 /* Not checking return, unreliable on native. Maybe it leaks references? */
2880 IPSFactoryBuffer_Release(psfb);
2881
2882 ok_more_than_one_lock();
2883
2884 IRpcStubBuffer_Disconnect(stub);
2885
2886 ok_no_locks();
2887
2888 refs = IRpcStubBuffer_Release(stub);
2889 ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2890 }
2891
2892 static HWND hwnd_app;
2893
TestRE_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)2894 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
2895 LPCLASSFACTORY iface,
2896 LPUNKNOWN pUnkOuter,
2897 REFIID riid,
2898 LPVOID *ppvObj)
2899 {
2900 DWORD_PTR res;
2901 if (IsEqualIID(riid, &IID_IWineTest))
2902 {
2903 BOOL ret = SendMessageTimeoutA(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
2904 ok(ret, "Timed out sending a message to originating window during RPC call\n");
2905 }
2906 *ppvObj = NULL;
2907 return S_FALSE;
2908 }
2909
2910 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
2911 {
2912 Test_IClassFactory_QueryInterface,
2913 Test_IClassFactory_AddRef,
2914 Test_IClassFactory_Release,
2915 TestRE_IClassFactory_CreateInstance,
2916 Test_IClassFactory_LockServer
2917 };
2918
2919 static IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
2920
window_proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)2921 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2922 {
2923 switch (msg)
2924 {
2925 case WM_USER:
2926 {
2927 HRESULT hr;
2928 IStream *pStream = NULL;
2929 IClassFactory *proxy = NULL;
2930 IUnknown *object;
2931 DWORD tid;
2932 HANDLE thread;
2933
2934 cLocks = 0;
2935
2936 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2937 ok_ole_success(hr, CreateStreamOnHGlobal);
2938 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2939
2940 ok_more_than_one_lock();
2941
2942 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2943 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2944 ok_ole_success(hr, CoReleaseMarshalData);
2945 IStream_Release(pStream);
2946
2947 ok_more_than_one_lock();
2948
2949 /* note the use of the magic IID_IWineTest value to tell remote thread
2950 * to try to send a message back to us */
2951 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IWineTest, (void **)&object);
2952 ok(hr == S_FALSE, "expected S_FALSE, got %d\n", hr);
2953
2954 IClassFactory_Release(proxy);
2955
2956 ok_no_locks();
2957
2958 end_host_object(tid, thread);
2959
2960 PostMessageA(hwnd, WM_QUIT, 0, 0);
2961
2962 return 0;
2963 }
2964 case WM_USER+1:
2965 {
2966 HRESULT hr;
2967 IStream *pStream = NULL;
2968 IClassFactory *proxy = NULL;
2969 IUnknown *object;
2970 DWORD tid;
2971 HANDLE thread;
2972
2973 cLocks = 0;
2974
2975 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2976 ok_ole_success(hr, CreateStreamOnHGlobal);
2977 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2978
2979 ok_more_than_one_lock();
2980
2981 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2982 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2983 ok_ole_success(hr, CoReleaseMarshalData);
2984 IStream_Release(pStream);
2985
2986 ok_more_than_one_lock();
2987
2988 /* post quit message before a doing a COM call to show that a pending
2989 * WM_QUIT message doesn't stop the call from succeeding */
2990 PostMessageA(hwnd, WM_QUIT, 0, 0);
2991 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
2992 ok(hr == S_FALSE, "IClassFactory_CreateInstance returned 0x%08x, expected S_FALSE\n", hr);
2993
2994 IClassFactory_Release(proxy);
2995
2996 ok_no_locks();
2997
2998 end_host_object(tid, thread);
2999
3000 return 0;
3001 }
3002 case WM_USER+2:
3003 {
3004 HRESULT hr;
3005 IStream *pStream = NULL;
3006 IClassFactory *proxy = NULL;
3007 IUnknown *object;
3008 DWORD tid;
3009 HANDLE thread;
3010
3011 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3012 ok_ole_success(hr, CreateStreamOnHGlobal);
3013 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3014
3015 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3016 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
3017 ok_ole_success(hr, CoReleaseMarshalData);
3018 IStream_Release(pStream);
3019
3020 /* shows that COM calls executed during the processing of sent
3021 * messages should fail */
3022 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
3023 ok(hr == RPC_E_CANTCALLOUT_ININPUTSYNCCALL,
3024 "COM call during processing of sent message should return RPC_E_CANTCALLOUT_ININPUTSYNCCALL instead of 0x%08x\n", hr);
3025
3026 IClassFactory_Release(proxy);
3027
3028 end_host_object(tid, thread);
3029
3030 PostQuitMessage(0);
3031
3032 return 0;
3033 }
3034 default:
3035 return DefWindowProcA(hwnd, msg, wparam, lparam);
3036 }
3037 }
3038
register_test_window(void)3039 static void register_test_window(void)
3040 {
3041 WNDCLASSA wndclass;
3042
3043 memset(&wndclass, 0, sizeof(wndclass));
3044 wndclass.lpfnWndProc = window_proc;
3045 wndclass.lpszClassName = "WineCOMTest";
3046 RegisterClassA(&wndclass);
3047 }
3048
test_message_reentrancy(void)3049 static void test_message_reentrancy(void)
3050 {
3051 MSG msg;
3052
3053 hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3054 ok(hwnd_app != NULL, "Window creation failed\n");
3055
3056 /* start message re-entrancy test */
3057 PostMessageA(hwnd_app, WM_USER, 0, 0);
3058
3059 while (GetMessageA(&msg, NULL, 0, 0))
3060 {
3061 TranslateMessage(&msg);
3062 DispatchMessageA(&msg);
3063 }
3064 DestroyWindow(hwnd_app);
3065 }
3066
TestMsg_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)3067 static HRESULT WINAPI TestMsg_IClassFactory_CreateInstance(
3068 LPCLASSFACTORY iface,
3069 LPUNKNOWN pUnkOuter,
3070 REFIID riid,
3071 LPVOID *ppvObj)
3072 {
3073 *ppvObj = NULL;
3074 SendMessageA(hwnd_app, WM_USER+2, 0, 0);
3075 return S_OK;
3076 }
3077
3078 static IClassFactoryVtbl TestMsgClassFactory_Vtbl =
3079 {
3080 Test_IClassFactory_QueryInterface,
3081 Test_IClassFactory_AddRef,
3082 Test_IClassFactory_Release,
3083 TestMsg_IClassFactory_CreateInstance,
3084 Test_IClassFactory_LockServer
3085 };
3086
3087 static IClassFactory TestMsg_ClassFactory = { &TestMsgClassFactory_Vtbl };
3088
test_call_from_message(void)3089 static void test_call_from_message(void)
3090 {
3091 MSG msg;
3092 IStream *pStream;
3093 HRESULT hr;
3094 IClassFactory *proxy;
3095 DWORD tid;
3096 HANDLE thread;
3097 IUnknown *object;
3098
3099 hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3100 ok(hwnd_app != NULL, "Window creation failed\n");
3101
3102 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3103 ok_ole_success(hr, CreateStreamOnHGlobal);
3104 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestMsg_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3105
3106 ok_more_than_one_lock();
3107
3108 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3109 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
3110 ok_ole_success(hr, CoReleaseMarshalData);
3111 IStream_Release(pStream);
3112
3113 ok_more_than_one_lock();
3114
3115 /* start message re-entrancy test */
3116 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
3117 ok_ole_success(hr, IClassFactory_CreateInstance);
3118
3119 IClassFactory_Release(proxy);
3120
3121 ok_no_locks();
3122
3123 end_host_object(tid, thread);
3124
3125 while (GetMessageA(&msg, NULL, 0, 0))
3126 {
3127 TranslateMessage(&msg);
3128 DispatchMessageA(&msg);
3129 }
3130 DestroyWindow(hwnd_app);
3131 }
3132
test_WM_QUIT_handling(void)3133 static void test_WM_QUIT_handling(void)
3134 {
3135 MSG msg;
3136
3137 hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3138 ok(hwnd_app != NULL, "Window creation failed\n");
3139
3140 /* start WM_QUIT handling test */
3141 PostMessageA(hwnd_app, WM_USER+1, 0, 0);
3142
3143 while (GetMessageA(&msg, NULL, 0, 0))
3144 {
3145 TranslateMessage(&msg);
3146 DispatchMessageA(&msg);
3147 }
3148 }
3149
round_global_size(SIZE_T size)3150 static SIZE_T round_global_size(SIZE_T size)
3151 {
3152 static SIZE_T global_size_alignment = -1;
3153 if (global_size_alignment == -1)
3154 {
3155 void *p = GlobalAlloc(GMEM_FIXED, 1);
3156 global_size_alignment = GlobalSize(p);
3157 GlobalFree(p);
3158 }
3159
3160 return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1));
3161 }
3162
test_freethreadedmarshaldata(IStream * pStream,MSHCTX mshctx,void * ptr,DWORD mshlflags)3163 static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *ptr, DWORD mshlflags)
3164 {
3165 HGLOBAL hglobal;
3166 DWORD size;
3167 char *marshal_data;
3168 HRESULT hr;
3169
3170 hr = GetHGlobalFromStream(pStream, &hglobal);
3171 ok_ole_success(hr, GetHGlobalFromStream);
3172
3173 size = GlobalSize(hglobal);
3174
3175 marshal_data = GlobalLock(hglobal);
3176
3177 if (mshctx == MSHCTX_INPROC)
3178 {
3179 DWORD expected_size = round_global_size(3*sizeof(DWORD) + sizeof(GUID));
3180 ok(size == expected_size ||
3181 broken(size == (2*sizeof(DWORD))) /* Win9x & NT4 */,
3182 "size should have been %d instead of %d\n", expected_size, size);
3183
3184 ok(*(DWORD *)marshal_data == mshlflags, "expected 0x%x, but got 0x%x for mshctx\n", mshlflags, *(DWORD *)marshal_data);
3185 marshal_data += sizeof(DWORD);
3186 ok(*(void **)marshal_data == ptr, "expected %p, but got %p for mshctx\n", ptr, *(void **)marshal_data);
3187 marshal_data += sizeof(void *);
3188 if (sizeof(void*) == 4 && size >= 3*sizeof(DWORD))
3189 {
3190 ok(*(DWORD *)marshal_data == 0, "expected 0x0, but got 0x%x\n", *(DWORD *)marshal_data);
3191 marshal_data += sizeof(DWORD);
3192 }
3193 if (size >= 3*sizeof(DWORD) + sizeof(GUID))
3194 {
3195 trace("got guid data: %s\n", wine_dbgstr_guid((GUID *)marshal_data));
3196 }
3197 }
3198 else
3199 {
3200 ok(size > sizeof(DWORD), "size should have been > sizeof(DWORD), not %d\n", size);
3201 ok(*(DWORD *)marshal_data == 0x574f454d /* MEOW */,
3202 "marshal data should be filled by standard marshal and start with MEOW signature\n");
3203 }
3204
3205 GlobalUnlock(hglobal);
3206 }
3207
test_freethreadedmarshaler(void)3208 static void test_freethreadedmarshaler(void)
3209 {
3210 HRESULT hr;
3211 IUnknown *pFTUnknown;
3212 IMarshal *pFTMarshal;
3213 IStream *pStream;
3214 IUnknown *pProxy;
3215 static const LARGE_INTEGER llZero;
3216 CLSID clsid;
3217
3218 cLocks = 0;
3219 hr = CoCreateFreeThreadedMarshaler(NULL, &pFTUnknown);
3220 ok_ole_success(hr, CoCreateFreeThreadedMarshaler);
3221 hr = IUnknown_QueryInterface(pFTUnknown, &IID_IMarshal, (void **)&pFTMarshal);
3222 ok_ole_success(hr, IUnknown_QueryInterface);
3223 IUnknown_Release(pFTUnknown);
3224
3225 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3226 ok_ole_success(hr, CreateStreamOnHGlobal);
3227
3228 /* inproc normal marshaling */
3229
3230 hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory,
3231 &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid);
3232 ok_ole_success(hr, IMarshal_GetUnmarshalClass);
3233 ok(IsEqualIID(&clsid, &CLSID_InProcFreeMarshaler), "clsid = %s\n",
3234 wine_dbgstr_guid(&clsid));
3235
3236 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3237 &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3238 ok_ole_success(hr, IMarshal_MarshalInterface);
3239
3240 ok_more_than_one_lock();
3241
3242 test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_NORMAL);
3243
3244 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3245 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3246 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3247
3248 IUnknown_Release(pProxy);
3249
3250 ok_no_locks();
3251
3252 /* inproc table-strong marshaling */
3253
3254 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3255 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3256 (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
3257 MSHLFLAGS_TABLESTRONG);
3258 ok_ole_success(hr, IMarshal_MarshalInterface);
3259
3260 ok_more_than_one_lock();
3261
3262 test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLESTRONG);
3263
3264 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3265 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3266 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3267
3268 IUnknown_Release(pProxy);
3269
3270 ok_more_than_one_lock();
3271
3272 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3273 hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
3274 ok_ole_success(hr, IMarshal_ReleaseMarshalData);
3275
3276 ok_no_locks();
3277
3278 /* inproc table-weak marshaling */
3279
3280 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3281 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3282 (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
3283 MSHLFLAGS_TABLEWEAK);
3284 ok_ole_success(hr, IMarshal_MarshalInterface);
3285
3286 ok_no_locks();
3287
3288 test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLEWEAK);
3289
3290 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3291 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3292 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3293
3294 ok_more_than_one_lock();
3295
3296 IUnknown_Release(pProxy);
3297
3298 ok_no_locks();
3299
3300 /* inproc normal marshaling (for extraordinary cases) */
3301
3302 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3303 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3304 &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3305 ok_ole_success(hr, IMarshal_MarshalInterface);
3306
3307 ok_more_than_one_lock();
3308
3309 /* this call shows that DisconnectObject does nothing */
3310 hr = IMarshal_DisconnectObject(pFTMarshal, 0);
3311 ok_ole_success(hr, IMarshal_DisconnectObject);
3312
3313 ok_more_than_one_lock();
3314
3315 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3316 hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
3317 ok_ole_success(hr, IMarshal_ReleaseMarshalData);
3318
3319 ok_no_locks();
3320
3321 /* doesn't enforce marshaling rules here and allows us to unmarshal the
3322 * interface, even though it was freed above */
3323 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3324 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3325 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3326
3327 ok_no_locks();
3328
3329 /* local normal marshaling */
3330
3331 hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory,
3332 &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL, &clsid);
3333 ok_ole_success(hr, IMarshal_GetUnmarshalClass);
3334 ok(IsEqualIID(&clsid, &CLSID_StdMarshal), "clsid = %s\n",
3335 wine_dbgstr_guid(&clsid));
3336
3337 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3338 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
3339 ok_ole_success(hr, IMarshal_MarshalInterface);
3340
3341 ok_more_than_one_lock();
3342
3343 test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL);
3344
3345 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3346 hr = CoReleaseMarshalData(pStream);
3347 ok_ole_success(hr, CoReleaseMarshalData);
3348
3349 ok_no_locks();
3350
3351 IStream_Release(pStream);
3352 IMarshal_Release(pFTMarshal);
3353 }
3354
reg_unreg_wine_test_class(BOOL Register)3355 static HRESULT reg_unreg_wine_test_class(BOOL Register)
3356 {
3357 HRESULT hr;
3358 char buffer[256];
3359 LPOLESTR pszClsid;
3360 HKEY hkey;
3361 DWORD dwDisposition;
3362 DWORD error;
3363
3364 hr = StringFromCLSID(&CLSID_WineTest, &pszClsid);
3365 ok_ole_success(hr, "StringFromCLSID");
3366 strcpy(buffer, "CLSID\\");
3367 WideCharToMultiByte(CP_ACP, 0, pszClsid, -1, buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), NULL, NULL);
3368 CoTaskMemFree(pszClsid);
3369 strcat(buffer, "\\InprocHandler32");
3370 if (Register)
3371 {
3372 error = RegCreateKeyExA(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
3373 if (error == ERROR_ACCESS_DENIED)
3374 {
3375 skip("Not authorized to modify the Classes key\n");
3376 return E_FAIL;
3377 }
3378 ok(error == ERROR_SUCCESS, "RegCreateKeyEx failed with error %d\n", error);
3379 if (error != ERROR_SUCCESS) hr = E_FAIL;
3380 error = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const unsigned char *)"\"ole32.dll\"", strlen("\"ole32.dll\"") + 1);
3381 ok(error == ERROR_SUCCESS, "RegSetValueEx failed with error %d\n", error);
3382 if (error != ERROR_SUCCESS) hr = E_FAIL;
3383 RegCloseKey(hkey);
3384 }
3385 else
3386 {
3387 RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3388 *strrchr(buffer, '\\') = '\0';
3389 RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3390 }
3391 return hr;
3392 }
3393
test_inproc_handler(void)3394 static void test_inproc_handler(void)
3395 {
3396 HRESULT hr;
3397 IUnknown *pObject;
3398 IUnknown *pObject2;
3399
3400 if (FAILED(reg_unreg_wine_test_class(TRUE)))
3401 return;
3402
3403 hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pObject);
3404 ok_ole_success(hr, "CoCreateInstance");
3405
3406 if (SUCCEEDED(hr))
3407 {
3408 hr = IUnknown_QueryInterface(pObject, &IID_IWineTest, (void **)&pObject2);
3409 ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface on handler for invalid interface returned 0x%08x instead of E_NOINTERFACE\n", hr);
3410
3411 /* it's a handler as it supports IOleObject */
3412 hr = IUnknown_QueryInterface(pObject, &IID_IOleObject, (void **)&pObject2);
3413 ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3414 IUnknown_Release(pObject2);
3415
3416 IUnknown_Release(pObject);
3417 }
3418
3419 reg_unreg_wine_test_class(FALSE);
3420 }
3421
Test_SMI_QueryInterface(IStdMarshalInfo * iface,REFIID riid,LPVOID * ppvObj)3422 static HRESULT WINAPI Test_SMI_QueryInterface(
3423 IStdMarshalInfo *iface,
3424 REFIID riid,
3425 LPVOID *ppvObj)
3426 {
3427 if (ppvObj == NULL) return E_POINTER;
3428
3429 if (IsEqualGUID(riid, &IID_IUnknown) ||
3430 IsEqualGUID(riid, &IID_IStdMarshalInfo))
3431 {
3432 *ppvObj = iface;
3433 IStdMarshalInfo_AddRef(iface);
3434 return S_OK;
3435 }
3436
3437 return E_NOINTERFACE;
3438 }
3439
Test_SMI_AddRef(IStdMarshalInfo * iface)3440 static ULONG WINAPI Test_SMI_AddRef(IStdMarshalInfo *iface)
3441 {
3442 LockModule();
3443 return 2; /* non-heap-based object */
3444 }
3445
Test_SMI_Release(IStdMarshalInfo * iface)3446 static ULONG WINAPI Test_SMI_Release(IStdMarshalInfo *iface)
3447 {
3448 UnlockModule();
3449 return 1; /* non-heap-based object */
3450 }
3451
Test_SMI_GetClassForHandler(IStdMarshalInfo * iface,DWORD dwDestContext,void * pvDestContext,CLSID * pClsid)3452 static HRESULT WINAPI Test_SMI_GetClassForHandler(
3453 IStdMarshalInfo *iface,
3454 DWORD dwDestContext,
3455 void *pvDestContext,
3456 CLSID *pClsid)
3457 {
3458 *pClsid = CLSID_WineTest;
3459 return S_OK;
3460 }
3461
3462 static const IStdMarshalInfoVtbl Test_SMI_Vtbl =
3463 {
3464 Test_SMI_QueryInterface,
3465 Test_SMI_AddRef,
3466 Test_SMI_Release,
3467 Test_SMI_GetClassForHandler
3468 };
3469
3470 static IStdMarshalInfo Test_SMI = {&Test_SMI_Vtbl};
3471
test_handler_marshaling(void)3472 static void test_handler_marshaling(void)
3473 {
3474 HRESULT hr;
3475 IStream *pStream = NULL;
3476 IUnknown *pProxy = NULL;
3477 IUnknown *pObject;
3478 DWORD tid;
3479 HANDLE thread;
3480 static const LARGE_INTEGER ullZero;
3481
3482 if (FAILED(reg_unreg_wine_test_class(TRUE)))
3483 return;
3484 cLocks = 0;
3485
3486 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3487 ok_ole_success(hr, "CreateStreamOnHGlobal");
3488 tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_SMI, MSHLFLAGS_NORMAL, &thread);
3489
3490 ok_more_than_one_lock();
3491
3492 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3493 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
3494 ok_ole_success(hr, "CoUnmarshalInterface");
3495 IStream_Release(pStream);
3496
3497 if(hr == S_OK)
3498 {
3499 ok_more_than_one_lock();
3500
3501 hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject);
3502 ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface with unknown IID should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3503
3504 /* it's a handler as it supports IOleObject */
3505 hr = IUnknown_QueryInterface(pProxy, &IID_IOleObject, (void **)&pObject);
3506 todo_wine
3507 ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3508 if (SUCCEEDED(hr)) IUnknown_Release(pObject);
3509
3510 IUnknown_Release(pProxy);
3511
3512 ok_no_locks();
3513 }
3514
3515 end_host_object(tid, thread);
3516 reg_unreg_wine_test_class(FALSE);
3517
3518 /* FIXME: test IPersist interface has the same effect as IStdMarshalInfo */
3519 }
3520
3521
test_client_security(void)3522 static void test_client_security(void)
3523 {
3524 HRESULT hr;
3525 IStream *pStream = NULL;
3526 IClassFactory *pProxy = NULL;
3527 IUnknown *pProxy2 = NULL;
3528 IUnknown *pUnknown1 = NULL;
3529 IUnknown *pUnknown2 = NULL;
3530 IClientSecurity *pCliSec = NULL;
3531 IMarshal *pMarshal;
3532 DWORD tid;
3533 HANDLE thread;
3534 static const LARGE_INTEGER ullZero;
3535 DWORD dwAuthnSvc;
3536 DWORD dwAuthzSvc;
3537 OLECHAR *pServerPrincName;
3538 DWORD dwAuthnLevel;
3539 DWORD dwImpLevel;
3540 void *pAuthInfo;
3541 DWORD dwCapabilities;
3542 void *pv;
3543
3544 cLocks = 0;
3545
3546 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3547 ok_ole_success(hr, "CreateStreamOnHGlobal");
3548 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3549
3550 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3551 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
3552 ok_ole_success(hr, "CoUnmarshalInterface");
3553 IStream_Release(pStream);
3554
3555 hr = IClassFactory_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pUnknown1);
3556 ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3557
3558 hr = IClassFactory_QueryInterface(pProxy, &IID_IRemUnknown, (LPVOID*)&pProxy2);
3559 ok_ole_success(hr, "IUnknown_QueryInterface IID_IStream");
3560
3561 hr = IUnknown_QueryInterface(pProxy2, &IID_IUnknown, (LPVOID*)&pUnknown2);
3562 ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3563
3564 ok(pUnknown1 == pUnknown2, "both proxy's IUnknowns should be the same - %p, %p\n", pUnknown1, pUnknown2);
3565
3566 hr = IClassFactory_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pMarshal);
3567 ok_ole_success(hr, "IUnknown_QueryInterface IID_IMarshal");
3568
3569 hr = IClassFactory_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pCliSec);
3570 ok_ole_success(hr, "IUnknown_QueryInterface IID_IClientSecurity");
3571
3572 hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3573 todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket (all NULLs)");
3574
3575 hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pMarshal, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3576 todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_QueryBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3577
3578 hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3579 todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket");
3580
3581 hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, RPC_C_IMP_LEVEL_IMPERSONATE, pAuthInfo, dwCapabilities);
3582 todo_wine ok_ole_success(hr, "IClientSecurity_SetBlanket");
3583
3584 hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IWineTest, &pv);
3585 ok(hr == E_NOINTERFACE, "COM call should have succeeded instead of returning 0x%08x\n", hr);
3586
3587 hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pMarshal, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3588 todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_SetBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3589
3590 hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, 0xdeadbeef, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3591 todo_wine ok(hr == E_INVALIDARG, "IClientSecurity_SetBlanke with invalid dwAuthnSvc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
3592
3593 CoTaskMemFree(pServerPrincName);
3594
3595 hr = IClientSecurity_QueryBlanket(pCliSec, pUnknown1, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3596 todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket(IUnknown)");
3597
3598 CoTaskMemFree(pServerPrincName);
3599
3600 IClassFactory_Release(pProxy);
3601 IUnknown_Release(pProxy2);
3602 IUnknown_Release(pUnknown1);
3603 IUnknown_Release(pUnknown2);
3604 IMarshal_Release(pMarshal);
3605 IClientSecurity_Release(pCliSec);
3606
3607 end_host_object(tid, thread);
3608 }
3609
3610 static HANDLE heventShutdown;
3611
LockModuleOOP(void)3612 static void LockModuleOOP(void)
3613 {
3614 InterlockedIncrement(&cLocks); /* for test purposes only */
3615 CoAddRefServerProcess();
3616 }
3617
UnlockModuleOOP(void)3618 static void UnlockModuleOOP(void)
3619 {
3620 InterlockedDecrement(&cLocks); /* for test purposes only */
3621 if (!CoReleaseServerProcess())
3622 SetEvent(heventShutdown);
3623 }
3624
3625 static HWND hwnd_app;
3626
3627 struct local_server
3628 {
3629 IPersist IPersist_iface; /* a nice short interface */
3630 };
3631
local_server_QueryInterface(IPersist * iface,REFIID iid,void ** obj)3632 static HRESULT WINAPI local_server_QueryInterface(IPersist *iface, REFIID iid, void **obj)
3633 {
3634 *obj = NULL;
3635
3636 if (IsEqualGUID(iid, &IID_IUnknown) ||
3637 IsEqualGUID(iid, &IID_IPersist))
3638 *obj = iface;
3639
3640 if (*obj)
3641 {
3642 IPersist_AddRef(iface);
3643 return S_OK;
3644 }
3645 return E_NOINTERFACE;
3646 }
3647
local_server_AddRef(IPersist * iface)3648 static ULONG WINAPI local_server_AddRef(IPersist *iface)
3649 {
3650 return 2;
3651 }
3652
local_server_Release(IPersist * iface)3653 static ULONG WINAPI local_server_Release(IPersist *iface)
3654 {
3655 return 1;
3656 }
3657
local_server_GetClassID(IPersist * iface,CLSID * clsid)3658 static HRESULT WINAPI local_server_GetClassID(IPersist *iface, CLSID *clsid)
3659 {
3660 HRESULT hr;
3661
3662 *clsid = IID_IUnknown;
3663
3664 /* Test calling CoDisconnectObject within a COM call */
3665 hr = CoDisconnectObject((IUnknown *)iface, 0);
3666 ok(hr == S_OK, "got %08x\n", hr);
3667
3668 /* Initialize and uninitialize the apartment to show that we
3669 * remain in the autojoined mta */
3670 hr = pCoInitializeEx( NULL, COINIT_MULTITHREADED );
3671 ok( hr == S_FALSE, "got %08x\n", hr );
3672 CoUninitialize();
3673
3674 return S_OK;
3675 }
3676
3677 static const IPersistVtbl local_server_persist_vtbl =
3678 {
3679 local_server_QueryInterface,
3680 local_server_AddRef,
3681 local_server_Release,
3682 local_server_GetClassID
3683 };
3684
3685 struct local_server local_server_class =
3686 {
3687 {&local_server_persist_vtbl}
3688 };
3689
TestOOP_IClassFactory_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID * ppvObj)3690 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
3691 LPCLASSFACTORY iface,
3692 REFIID riid,
3693 LPVOID *ppvObj)
3694 {
3695 if (ppvObj == NULL) return E_POINTER;
3696
3697 if (IsEqualGUID(riid, &IID_IUnknown) ||
3698 IsEqualGUID(riid, &IID_IClassFactory))
3699 {
3700 *ppvObj = iface;
3701 IClassFactory_AddRef(iface);
3702 return S_OK;
3703 }
3704
3705 return E_NOINTERFACE;
3706 }
3707
TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)3708 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
3709 {
3710 return 2; /* non-heap-based object */
3711 }
3712
TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)3713 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
3714 {
3715 return 1; /* non-heap-based object */
3716 }
3717
TestOOP_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)3718 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
3719 LPCLASSFACTORY iface,
3720 LPUNKNOWN pUnkOuter,
3721 REFIID riid,
3722 LPVOID *ppvObj)
3723 {
3724 IPersist *persist = &local_server_class.IPersist_iface;
3725 HRESULT hr;
3726 IPersist_AddRef( persist );
3727 hr = IPersist_QueryInterface( persist, riid, ppvObj );
3728 IPersist_Release( persist );
3729 return hr;
3730 }
3731
TestOOP_IClassFactory_LockServer(LPCLASSFACTORY iface,BOOL fLock)3732 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
3733 LPCLASSFACTORY iface,
3734 BOOL fLock)
3735 {
3736 if (fLock)
3737 LockModuleOOP();
3738 else
3739 UnlockModuleOOP();
3740 return S_OK;
3741 }
3742
3743 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
3744 {
3745 TestOOP_IClassFactory_QueryInterface,
3746 TestOOP_IClassFactory_AddRef,
3747 TestOOP_IClassFactory_Release,
3748 TestOOP_IClassFactory_CreateInstance,
3749 TestOOP_IClassFactory_LockServer
3750 };
3751
3752 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
3753
test_register_local_server(void)3754 static void test_register_local_server(void)
3755 {
3756 DWORD cookie;
3757 HRESULT hr;
3758 HANDLE ready_event;
3759 DWORD wait;
3760 HANDLE handles[2];
3761
3762 heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3763 ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3764 handles[0] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3765 handles[1] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3766
3767 again:
3768 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3769 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
3770 ok_ole_success(hr, CoRegisterClassObject);
3771
3772 SetEvent(ready_event);
3773
3774 do
3775 {
3776 wait = MsgWaitForMultipleObjects(2, handles, FALSE, 30000, QS_ALLINPUT);
3777 if (wait == WAIT_OBJECT_0+2)
3778 {
3779 MSG msg;
3780
3781 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
3782 {
3783 trace("Message 0x%x\n", msg.message);
3784 TranslateMessage(&msg);
3785 DispatchMessageA(&msg);
3786 }
3787 }
3788 else if (wait == WAIT_OBJECT_0+1)
3789 {
3790 hr = CoRevokeClassObject(cookie);
3791 ok_ole_success(hr, CoRevokeClassObject);
3792 goto again;
3793 }
3794 }
3795 while (wait == WAIT_OBJECT_0+2);
3796
3797 ok( wait == WAIT_OBJECT_0, "quit event wait timed out\n" );
3798 hr = CoRevokeClassObject(cookie);
3799 ok_ole_success(hr, CoRevokeClassObject);
3800 CloseHandle(handles[0]);
3801 CloseHandle(handles[1]);
3802 }
3803
create_target_process(const char * arg)3804 static HANDLE create_target_process(const char *arg)
3805 {
3806 char **argv;
3807 char cmdline[MAX_PATH];
3808 BOOL ret;
3809 PROCESS_INFORMATION pi;
3810 STARTUPINFOA si = { 0 };
3811 si.cb = sizeof(si);
3812
3813 pi.hThread = NULL;
3814 pi.hProcess = NULL;
3815 winetest_get_mainargs( &argv );
3816 sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], arg);
3817 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3818 ok(ret, "CreateProcess failed with error: %u\n", GetLastError());
3819 if (pi.hThread) CloseHandle(pi.hThread);
3820 return pi.hProcess;
3821 }
3822
3823 /* tests functions commonly used by out of process COM servers */
test_local_server(void)3824 static void test_local_server(void)
3825 {
3826 DWORD cookie;
3827 HRESULT hr;
3828 IClassFactory * cf;
3829 IPersist *persist;
3830 DWORD ret;
3831 HANDLE process;
3832 HANDLE quit_event;
3833 HANDLE ready_event;
3834 HANDLE repeat_event;
3835 CLSID clsid;
3836
3837 heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3838
3839 cLocks = 0;
3840
3841 /* Start the object suspended */
3842 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3843 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
3844 ok_ole_success(hr, CoRegisterClassObject);
3845
3846 /* ... and CoGetClassObject does not find it and fails when it looks for the
3847 * class in the registry */
3848 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3849 NULL, &IID_IClassFactory, (LPVOID*)&cf);
3850 ok(hr == REGDB_E_CLASSNOTREG || /* NT */
3851 hr == S_OK /* Win9x */,
3852 "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3853
3854 /* Resume the object suspended above ... */
3855 hr = CoResumeClassObjects();
3856 ok_ole_success(hr, CoResumeClassObjects);
3857
3858 /* ... and now it should succeed */
3859 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3860 NULL, &IID_IClassFactory, (LPVOID*)&cf);
3861 ok_ole_success(hr, CoGetClassObject);
3862
3863 /* Now check the locking is working */
3864 /* NOTE: we are accessing the class directly, not through a proxy */
3865
3866 ok_no_locks();
3867
3868 hr = IClassFactory_LockServer(cf, TRUE);
3869 ok_ole_success(hr, IClassFactory_LockServer);
3870
3871 ok_more_than_one_lock();
3872
3873 IClassFactory_LockServer(cf, FALSE);
3874 ok_ole_success(hr, IClassFactory_LockServer);
3875
3876 ok_no_locks();
3877
3878 IClassFactory_Release(cf);
3879
3880 /* wait for shutdown signal */
3881 ret = WaitForSingleObject(heventShutdown, 0);
3882 ok(ret != WAIT_TIMEOUT, "Server didn't shut down\n");
3883
3884 /* try to connect again after SCM has suspended registered class objects */
3885 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
3886 &IID_IClassFactory, (LPVOID*)&cf);
3887 ok(hr == CO_E_SERVER_STOPPING || /* NT */
3888 hr == REGDB_E_CLASSNOTREG || /* win2k */
3889 hr == S_OK /* Win9x */,
3890 "CoGetClassObject should have returned CO_E_SERVER_STOPPING or REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3891
3892 hr = CoRevokeClassObject(cookie);
3893 ok_ole_success(hr, CoRevokeClassObject);
3894
3895 CloseHandle(heventShutdown);
3896
3897 process = create_target_process("-Embedding");
3898 ok(process != NULL, "couldn't start local server process, error was %d\n", GetLastError());
3899
3900 ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3901 ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3902
3903 hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3904 ok_ole_success(hr, CoCreateInstance);
3905
3906 IPersist_Release(persist);
3907
3908 hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3909 ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n");
3910
3911 /* Re-register the class and try calling CoDisconnectObject from within a call to that object */
3912 repeat_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3913 SetEvent(repeat_event);
3914 CloseHandle(repeat_event);
3915
3916 ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3917 CloseHandle(ready_event);
3918
3919 hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3920 ok_ole_success(hr, CoCreateInstance);
3921
3922 /* GetClassID will call CoDisconnectObject */
3923 IPersist_GetClassID(persist, &clsid);
3924 IPersist_Release(persist);
3925
3926 quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3927 SetEvent(quit_event);
3928
3929 winetest_wait_child_process( process );
3930 CloseHandle(quit_event);
3931 CloseHandle(process);
3932 }
3933
3934 struct git_params
3935 {
3936 DWORD cookie;
3937 IGlobalInterfaceTable *git;
3938 };
3939
get_global_interface_proc(LPVOID pv)3940 static DWORD CALLBACK get_global_interface_proc(LPVOID pv)
3941 {
3942 HRESULT hr;
3943 struct git_params *params = pv;
3944 IClassFactory *cf;
3945
3946 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3947 ok(hr == CO_E_NOTINITIALIZED ||
3948 broken(hr == E_UNEXPECTED) /* win2k */ ||
3949 broken(hr == S_OK) /* NT 4 */,
3950 "IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED or E_UNEXPECTED instead of 0x%08x\n",
3951 hr);
3952 if (hr == S_OK)
3953 IClassFactory_Release(cf);
3954
3955 CoInitialize(NULL);
3956
3957 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3958 ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
3959
3960 IClassFactory_Release(cf);
3961
3962 CoUninitialize();
3963
3964 return hr;
3965 }
3966
test_globalinterfacetable(void)3967 static void test_globalinterfacetable(void)
3968 {
3969 HRESULT hr;
3970 IGlobalInterfaceTable *git;
3971 DWORD cookie;
3972 HANDLE thread;
3973 DWORD tid;
3974 struct git_params params;
3975 DWORD ret;
3976 IUnknown *object;
3977 IClassFactory *cf;
3978 ULONG ref;
3979
3980 trace("test_globalinterfacetable\n");
3981 cLocks = 0;
3982
3983 hr = pDllGetClassObject(&CLSID_StdGlobalInterfaceTable, &IID_IClassFactory, (void**)&cf);
3984 ok(hr == S_OK, "got 0x%08x\n", hr);
3985
3986 hr = IClassFactory_QueryInterface(cf, &IID_IGlobalInterfaceTable, (void**)&object);
3987 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
3988
3989 IClassFactory_Release(cf);
3990
3991 hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)&git);
3992 ok_ole_success(hr, CoCreateInstance);
3993
3994 ref = IGlobalInterfaceTable_AddRef(git);
3995 ok(ref == 1, "ref=%d\n", ref);
3996 ref = IGlobalInterfaceTable_AddRef(git);
3997 ok(ref == 1, "ref=%d\n", ref);
3998
3999 ref = IGlobalInterfaceTable_Release(git);
4000 ok(ref == 1, "ref=%d\n", ref);
4001 ref = IGlobalInterfaceTable_Release(git);
4002 ok(ref == 1, "ref=%d\n", ref);
4003
4004 hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&Test_ClassFactory, &IID_IClassFactory, &cookie);
4005 ok_ole_success(hr, IGlobalInterfaceTable_RegisterInterfaceInGlobal);
4006
4007 ok_more_than_one_lock();
4008
4009 params.cookie = cookie;
4010 params.git = git;
4011 /* note: params is on stack so we MUST wait for get_global_interface_proc
4012 * to exit before we can return */
4013 thread = CreateThread(NULL, 0, get_global_interface_proc, ¶ms, 0, &tid);
4014
4015 ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
4016 while (ret == WAIT_OBJECT_0 + 1)
4017 {
4018 MSG msg;
4019 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
4020 DispatchMessageA(&msg);
4021 ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
4022 }
4023
4024 CloseHandle(thread);
4025
4026 /* test getting interface from global with different iid */
4027 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IUnknown, (void **)&object);
4028 ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
4029 IUnknown_Release(object);
4030
4031 /* test getting interface from global with same iid */
4032 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IClassFactory, (void **)&object);
4033 ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
4034 IUnknown_Release(object);
4035
4036 hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, cookie);
4037 ok_ole_success(hr, IGlobalInterfaceTable_RevokeInterfaceFromGlobal);
4038
4039 ok_no_locks();
4040
4041 IGlobalInterfaceTable_Release(git);
4042 }
4043
test_manualresetevent(void)4044 static void test_manualresetevent(void)
4045 {
4046 ISynchronizeHandle *sync_handle;
4047 ISynchronize *psync1, *psync2;
4048 IUnknown *punk;
4049 HANDLE handle;
4050 LONG ref;
4051 HRESULT hr;
4052
4053 hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&punk);
4054 ok(hr == S_OK, "Got 0x%08x\n", hr);
4055 ok(!!punk, "Got NULL.\n");
4056 IUnknown_Release(punk);
4057
4058 hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync1);
4059 ok(hr == S_OK, "Got 0x%08x\n", hr);
4060 ok(!!psync1, "Got NULL.\n");
4061
4062 hr = ISynchronize_Wait(psync1, 0, 5);
4063 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4064
4065 hr = ISynchronize_Reset(psync1);
4066 ok(hr == S_OK, "Got 0x%08x\n", hr);
4067 hr = ISynchronize_Signal(psync1);
4068 ok(hr == S_OK, "Got 0x%08x\n", hr);
4069 hr = ISynchronize_Wait(psync1, 0, 5);
4070 ok(hr == S_OK, "Got 0x%08x\n", hr);
4071 hr = ISynchronize_Wait(psync1, 0, 5);
4072 ok(hr == S_OK, "Got 0x%08x\n", hr);
4073 hr = ISynchronize_Reset(psync1);
4074 ok(hr == S_OK, "Got 0x%08x\n", hr);
4075 hr = ISynchronize_Wait(psync1, 0, 5);
4076 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4077
4078 hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync2);
4079 ok(hr == S_OK, "Got 0x%08x\n", hr);
4080 ok(!!psync2, "Got NULL.\n");
4081 ok(psync1 != psync2, "psync1 == psync2.\n");
4082
4083 hr = ISynchronize_QueryInterface(psync2, &IID_ISynchronizeHandle, (void**)&sync_handle);
4084 ok(hr == S_OK, "QueryInterface(IID_ISynchronizeHandle) failed: %08x\n", hr);
4085
4086 handle = NULL;
4087 hr = ISynchronizeHandle_GetHandle(sync_handle, &handle);
4088 ok(hr == S_OK, "GetHandle failed: %08x\n", hr);
4089 ok(handle != NULL && handle != INVALID_HANDLE_VALUE, "handle = %p\n", handle);
4090
4091 ISynchronizeHandle_Release(sync_handle);
4092
4093 hr = ISynchronize_Wait(psync2, 0, 5);
4094 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4095
4096 hr = ISynchronize_Reset(psync1);
4097 ok(hr == S_OK, "Got 0x%08x\n", hr);
4098 hr = ISynchronize_Reset(psync2);
4099 ok(hr == S_OK, "Got 0x%08x\n", hr);
4100 hr = ISynchronize_Signal(psync1);
4101 ok(hr == S_OK, "Got 0x%08x\n", hr);
4102 hr = ISynchronize_Wait(psync2, 0, 5);
4103 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4104
4105 ref = ISynchronize_AddRef(psync1);
4106 ok(ref == 2, "Got ref: %d\n", ref);
4107 ref = ISynchronize_AddRef(psync1);
4108 ok(ref == 3, "Got ref: %d\n", ref);
4109 ref = ISynchronize_Release(psync1);
4110 ok(ref == 2, "Got nonzero ref: %d\n", ref);
4111 ref = ISynchronize_Release(psync2);
4112 ok(!ref, "Got nonzero ref: %d\n", ref);
4113 ref = ISynchronize_Release(psync1);
4114 ok(ref == 1, "Got nonzero ref: %d\n", ref);
4115 ref = ISynchronize_Release(psync1);
4116 ok(!ref, "Got nonzero ref: %d\n", ref);
4117 }
4118
implicit_mta_unmarshal_proc(void * param)4119 static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param)
4120 {
4121 IStream *stream = param;
4122 IClassFactory *cf;
4123 IUnknown *proxy;
4124 HRESULT hr;
4125
4126 IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
4127 hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
4128 ok_ole_success(hr, CoUnmarshalInterface);
4129
4130 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4131 ok_ole_success(hr, IClassFactory_CreateInstance);
4132
4133 IUnknown_Release(proxy);
4134
4135 /* But if we initialize an STA in this apartment, it becomes the wrong one. */
4136 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4137
4138 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4139 ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
4140
4141 CoUninitialize();
4142
4143 ok_more_than_one_lock();
4144 ok_non_zero_external_conn();
4145
4146 IClassFactory_Release(cf);
4147
4148 ok_no_locks();
4149 ok_zero_external_conn();
4150 ok_last_release_closes(TRUE);
4151 return 0;
4152 }
4153
implicit_mta_use_proc(void * param)4154 static DWORD CALLBACK implicit_mta_use_proc(void *param)
4155 {
4156 IClassFactory *cf = param;
4157 IUnknown *proxy;
4158 HRESULT hr;
4159
4160 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4161 ok_ole_success(hr, IClassFactory_CreateInstance);
4162
4163 IUnknown_Release(proxy);
4164
4165 /* But if we initialize an STA in this apartment, it becomes the wrong one. */
4166 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4167
4168 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4169 ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
4170
4171 CoUninitialize();
4172 return 0;
4173 }
4174
4175 struct implicit_mta_marshal_data
4176 {
4177 IStream *stream;
4178 HANDLE start;
4179 HANDLE stop;
4180 };
4181
implicit_mta_marshal_proc(void * param)4182 static DWORD CALLBACK implicit_mta_marshal_proc(void *param)
4183 {
4184 struct implicit_mta_marshal_data *data = param;
4185 HRESULT hr;
4186
4187 hr = CoMarshalInterface(data->stream, &IID_IClassFactory,
4188 (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
4189 ok_ole_success(hr, CoMarshalInterface);
4190
4191 SetEvent(data->start);
4192
4193 ok(!WaitForSingleObject(data->stop, 1000), "wait failed\n");
4194 return 0;
4195 }
4196
test_implicit_mta(void)4197 static void test_implicit_mta(void)
4198 {
4199 struct implicit_mta_marshal_data data;
4200 HANDLE host_thread, thread;
4201 IClassFactory *cf;
4202 IUnknown *proxy;
4203 IStream *stream;
4204 HRESULT hr;
4205 DWORD tid;
4206
4207 cLocks = 0;
4208 external_connections = 0;
4209
4210 CoInitializeEx(NULL, COINIT_MULTITHREADED);
4211
4212 /* Firstly: we can unmarshal and use an object while in the implicit MTA. */
4213 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4214 ok_ole_success(hr, CreateStreamOnHGlobal);
4215 tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
4216
4217 ok_more_than_one_lock();
4218 ok_non_zero_external_conn();
4219
4220 thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL);
4221 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4222 CloseHandle(thread);
4223
4224 IStream_Release(stream);
4225 end_host_object(tid, host_thread);
4226
4227 /* Secondly: we can unmarshal an object into the real MTA and then use it
4228 * from the implicit MTA. */
4229 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4230 ok_ole_success(hr, CreateStreamOnHGlobal);
4231 tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
4232
4233 ok_more_than_one_lock();
4234 ok_non_zero_external_conn();
4235
4236 IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
4237 hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
4238 ok_ole_success(hr, CoUnmarshalInterface);
4239
4240 thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL);
4241 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4242 CloseHandle(thread);
4243
4244 IClassFactory_Release(cf);
4245 IStream_Release(stream);
4246
4247 ok_no_locks();
4248 ok_non_zero_external_conn();
4249 ok_last_release_closes(TRUE);
4250
4251 end_host_object(tid, host_thread);
4252
4253 /* Thirdly: we can marshal an object from the implicit MTA and then
4254 * unmarshal it into the real one. */
4255 data.start = CreateEventA(NULL, FALSE, FALSE, NULL);
4256 data.stop = CreateEventA(NULL, FALSE, FALSE, NULL);
4257
4258 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.stream);
4259 ok_ole_success(hr, CreateStreamOnHGlobal);
4260
4261 thread = CreateThread(NULL, 0, implicit_mta_marshal_proc, &data, 0, NULL);
4262 ok(!WaitForSingleObject(data.start, 1000), "wait failed\n");
4263
4264 IStream_Seek(data.stream, ullZero, STREAM_SEEK_SET, NULL);
4265 hr = CoUnmarshalInterface(data.stream, &IID_IClassFactory, (void **)&cf);
4266 ok_ole_success(hr, CoUnmarshalInterface);
4267
4268 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4269 ok_ole_success(hr, IClassFactory_CreateInstance);
4270
4271 IUnknown_Release(proxy);
4272
4273 SetEvent(data.stop);
4274 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4275 CloseHandle(thread);
4276
4277 IStream_Release(data.stream);
4278
4279 CoUninitialize();
4280 }
4281
debugstr_iid(REFIID riid)4282 static const char *debugstr_iid(REFIID riid)
4283 {
4284 static char name[256];
4285 HKEY hkeyInterface;
4286 WCHAR bufferW[39];
4287 char buffer[39];
4288 LONG name_size = sizeof(name);
4289 StringFromGUID2(riid, bufferW, ARRAY_SIZE(bufferW));
4290 WideCharToMultiByte(CP_ACP, 0, bufferW, ARRAY_SIZE(bufferW), buffer, sizeof(buffer), NULL, NULL);
4291 if (RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS)
4292 {
4293 memcpy(name, buffer, sizeof(buffer));
4294 goto done;
4295 }
4296 if (RegQueryValueA(hkeyInterface, buffer, name, &name_size) != ERROR_SUCCESS)
4297 {
4298 memcpy(name, buffer, sizeof(buffer));
4299 goto done;
4300 }
4301 RegCloseKey(hkeyInterface);
4302 done:
4303 return name;
4304 }
4305
TestChannelHook_QueryInterface(IChannelHook * iface,REFIID riid,void ** ppv)4306 static HRESULT WINAPI TestChannelHook_QueryInterface(IChannelHook *iface, REFIID riid, void **ppv)
4307 {
4308 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IChannelHook))
4309 {
4310 *ppv = iface;
4311 IChannelHook_AddRef(iface);
4312 return S_OK;
4313 }
4314
4315 *ppv = NULL;
4316 return E_NOINTERFACE;
4317 }
4318
TestChannelHook_AddRef(IChannelHook * iface)4319 static ULONG WINAPI TestChannelHook_AddRef(IChannelHook *iface)
4320 {
4321 return 2;
4322 }
4323
TestChannelHook_Release(IChannelHook * iface)4324 static ULONG WINAPI TestChannelHook_Release(IChannelHook *iface)
4325 {
4326 return 1;
4327 }
4328
4329 static BOOL new_hook_struct;
4330 static int method, server_tid;
4331 static GUID causality;
4332
4333 struct new_hook_info
4334 {
4335 IID iid;
4336 GUID causality;
4337 DWORD server_pid;
4338 DWORD server_tid;
4339 WORD method;
4340 };
4341
TestChannelHook_ClientGetSize(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG * pDataSize)4342 static void WINAPI TestChannelHook_ClientGetSize(
4343 IChannelHook *iface,
4344 REFGUID uExtent,
4345 REFIID riid,
4346 ULONG *pDataSize )
4347 {
4348 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4349 trace("TestChannelHook_ClientGetSize\n");
4350 trace("\t%s\n", debugstr_iid(riid));
4351 if (info->cbSize != sizeof(*info))
4352 new_hook_struct = TRUE;
4353
4354 if (!new_hook_struct)
4355 {
4356 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4357 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4358 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4359 ok(!info->pObject, "pObject should be NULL\n");
4360 if (method == 3)
4361 causality = info->uCausality;
4362 else
4363 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4364 }
4365 else
4366 {
4367 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4368 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4369 GetCurrentProcessId());
4370 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4371 server_tid);
4372 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4373 if (method == 3)
4374 causality = new_info->causality;
4375 else
4376 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4377 }
4378
4379 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4380
4381 *pDataSize = 1;
4382 }
4383
TestChannelHook_ClientFillBuffer(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG * pDataSize,void * pDataBuffer)4384 static void WINAPI TestChannelHook_ClientFillBuffer(
4385 IChannelHook *iface,
4386 REFGUID uExtent,
4387 REFIID riid,
4388 ULONG *pDataSize,
4389 void *pDataBuffer )
4390 {
4391 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4392 trace("TestChannelHook_ClientFillBuffer\n");
4393
4394 if (!new_hook_struct)
4395 {
4396 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4397 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4398 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4399 ok(!info->pObject, "pObject should be NULL\n");
4400 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4401 }
4402 else
4403 {
4404 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4405 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4406 GetCurrentProcessId());
4407 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4408 server_tid);
4409 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4410 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4411 }
4412
4413 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4414
4415 *(unsigned char *)pDataBuffer = 0xcc;
4416 *pDataSize = 1;
4417 }
4418
TestChannelHook_ClientNotify(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG cbDataSize,void * pDataBuffer,DWORD lDataRep,HRESULT hrFault)4419 static void WINAPI TestChannelHook_ClientNotify(
4420 IChannelHook *iface,
4421 REFGUID uExtent,
4422 REFIID riid,
4423 ULONG cbDataSize,
4424 void *pDataBuffer,
4425 DWORD lDataRep,
4426 HRESULT hrFault )
4427 {
4428 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4429 trace("TestChannelHook_ClientNotify hrFault = 0x%08x\n", hrFault);
4430
4431 if (!new_hook_struct)
4432 {
4433 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4434 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4435 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4436 todo_wine {
4437 ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4438 }
4439 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4440 }
4441 else
4442 {
4443 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4444 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4445 GetCurrentProcessId());
4446 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4447 server_tid);
4448 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4449 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4450 }
4451
4452 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4453 }
4454
TestChannelHook_ServerNotify(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG cbDataSize,void * pDataBuffer,DWORD lDataRep)4455 static void WINAPI TestChannelHook_ServerNotify(
4456 IChannelHook *iface,
4457 REFGUID uExtent,
4458 REFIID riid,
4459 ULONG cbDataSize,
4460 void *pDataBuffer,
4461 DWORD lDataRep )
4462 {
4463 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4464 trace("TestChannelHook_ServerNotify\n");
4465
4466 if (!new_hook_struct)
4467 {
4468 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4469 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4470 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4471 ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4472 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4473 }
4474 else
4475 {
4476 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4477 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4478 GetCurrentProcessId());
4479 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4480 server_tid);
4481 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4482 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4483 }
4484
4485 ok(cbDataSize == 1, "cbDataSize should have been 1 instead of %d\n", cbDataSize);
4486 ok(*(unsigned char *)pDataBuffer == 0xcc, "pDataBuffer should have contained 0xcc instead of 0x%x\n", *(unsigned char *)pDataBuffer);
4487 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4488 }
4489
TestChannelHook_ServerGetSize(IChannelHook * iface,REFGUID uExtent,REFIID riid,HRESULT hrFault,ULONG * pDataSize)4490 static void WINAPI TestChannelHook_ServerGetSize(
4491 IChannelHook *iface,
4492 REFGUID uExtent,
4493 REFIID riid,
4494 HRESULT hrFault,
4495 ULONG *pDataSize )
4496 {
4497 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4498 trace("TestChannelHook_ServerGetSize\n");
4499 trace("\t%s\n", debugstr_iid(riid));
4500 if (!new_hook_struct)
4501 {
4502 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4503 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4504 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4505 ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4506 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4507 }
4508 else
4509 {
4510 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4511 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4512 GetCurrentProcessId());
4513 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4514 server_tid);
4515 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4516 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4517 }
4518
4519 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4520 if (hrFault != S_OK)
4521 trace("\thrFault = 0x%08x\n", hrFault);
4522
4523 *pDataSize = 0;
4524 }
4525
TestChannelHook_ServerFillBuffer(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG * pDataSize,void * pDataBuffer,HRESULT hrFault)4526 static void WINAPI TestChannelHook_ServerFillBuffer(
4527 IChannelHook *iface,
4528 REFGUID uExtent,
4529 REFIID riid,
4530 ULONG *pDataSize,
4531 void *pDataBuffer,
4532 HRESULT hrFault )
4533 {
4534 trace("TestChannelHook_ServerFillBuffer\n");
4535 ok(0, "TestChannelHook_ServerFillBuffer shouldn't be called\n");
4536 }
4537
4538 static const IChannelHookVtbl TestChannelHookVtbl =
4539 {
4540 TestChannelHook_QueryInterface,
4541 TestChannelHook_AddRef,
4542 TestChannelHook_Release,
4543 TestChannelHook_ClientGetSize,
4544 TestChannelHook_ClientFillBuffer,
4545 TestChannelHook_ClientNotify,
4546 TestChannelHook_ServerNotify,
4547 TestChannelHook_ServerGetSize,
4548 TestChannelHook_ServerFillBuffer,
4549 };
4550
4551 static IChannelHook TestChannelHook = { &TestChannelHookVtbl };
4552
test_channel_hook(void)4553 static void test_channel_hook(void)
4554 {
4555 IClassFactory *cf = NULL;
4556 DWORD tid;
4557 IUnknown *proxy = NULL;
4558 HANDLE thread;
4559 HRESULT hr;
4560
4561 struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
4562 MSHLFLAGS_NORMAL, &MessageFilter };
4563
4564 hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook);
4565 ok_ole_success(hr, CoRegisterChannelHook);
4566
4567 hr = CoRegisterMessageFilter(&MessageFilter, NULL);
4568 ok_ole_success(hr, CoRegisterMessageFilter);
4569
4570 cLocks = 0;
4571
4572 hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
4573 ok_ole_success(hr, CreateStreamOnHGlobal);
4574 tid = start_host_object2(&object_data, &thread);
4575 server_tid = tid;
4576
4577 ok_more_than_one_lock();
4578
4579 IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
4580 hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
4581 ok_ole_success(hr, CoUnmarshalInterface);
4582 IStream_Release(object_data.stream);
4583
4584 ok_more_than_one_lock();
4585
4586 method = 3;
4587 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
4588 ok_ole_success(hr, IClassFactory_CreateInstance);
4589
4590 method = 5;
4591 IUnknown_Release(proxy);
4592
4593 IClassFactory_Release(cf);
4594
4595 ok_no_locks();
4596
4597 end_host_object(tid, thread);
4598
4599 hr = CoRegisterMessageFilter(NULL, NULL);
4600 ok_ole_success(hr, CoRegisterMessageFilter);
4601 }
4602
START_TEST(marshal)4603 START_TEST(marshal)
4604 {
4605 HMODULE hOle32 = GetModuleHandleA("ole32");
4606 int argc;
4607 char **argv;
4608
4609 if (!GetProcAddress(hOle32, "CoRegisterSurrogateEx")) {
4610 win_skip("skipping test on win9x\n");
4611 return;
4612 }
4613
4614 pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
4615 pDllGetClassObject = (void*)GetProcAddress(hOle32, "DllGetClassObject");
4616
4617 argc = winetest_get_mainargs( &argv );
4618 if (argc > 2 && (!strcmp(argv[2], "-Embedding")))
4619 {
4620 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
4621 test_register_local_server();
4622 CoUninitialize();
4623
4624 return;
4625 }
4626
4627 register_test_window();
4628
4629 test_cocreateinstance_proxy();
4630 test_implicit_mta();
4631
4632 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4633
4634 /* FIXME: test CoCreateInstanceEx */
4635
4636 /* lifecycle management and marshaling tests */
4637 do
4638 {
4639 test_no_marshaler();
4640 test_normal_marshal_and_release();
4641 test_normal_marshal_and_unmarshal();
4642 test_marshal_and_unmarshal_invalid();
4643 test_same_apartment_unmarshal_failure();
4644 test_interthread_marshal_and_unmarshal();
4645 test_proxy_marshal_and_unmarshal();
4646 test_proxy_marshal_and_unmarshal2();
4647 test_proxy_marshal_and_unmarshal_weak();
4648 test_proxy_marshal_and_unmarshal_strong();
4649 test_marshal_stub_apartment_shutdown();
4650 test_marshal_proxy_apartment_shutdown();
4651 test_marshal_proxy_mta_apartment_shutdown();
4652 test_no_couninitialize_server();
4653 test_no_couninitialize_client();
4654 test_tableweak_marshal_and_unmarshal_twice();
4655 test_tableweak_marshal_releasedata1();
4656 test_tableweak_marshal_releasedata2();
4657 test_tableweak_and_normal_marshal_and_unmarshal();
4658 test_tableweak_and_normal_marshal_and_releasedata();
4659 test_two_tableweak_marshal_and_releasedata();
4660 test_tablestrong_marshal_and_unmarshal_twice();
4661 test_lock_object_external();
4662 test_disconnect_stub();
4663 test_normal_marshal_and_unmarshal_twice();
4664
4665 with_external_conn = !with_external_conn;
4666 } while (with_external_conn);
4667
4668 test_marshal_channel_buffer();
4669 test_StdMarshal_custom_marshaling();
4670 test_DfMarshal_custom_marshaling();
4671 test_CoGetStandardMarshal();
4672 test_hresult_marshaling();
4673 test_proxy_used_in_wrong_thread();
4674 test_message_filter();
4675 test_bad_marshal_stream();
4676 test_proxy_interfaces();
4677 test_stubbuffer(&IID_IClassFactory);
4678 test_proxybuffer(&IID_IClassFactory);
4679 test_message_reentrancy();
4680 test_call_from_message();
4681 test_WM_QUIT_handling();
4682 test_freethreadedmarshaler();
4683 test_inproc_handler();
4684 test_handler_marshaling();
4685 test_client_security();
4686
4687 test_local_server();
4688
4689 test_globalinterfacetable();
4690 test_manualresetevent();
4691 test_crash_couninitialize();
4692
4693 /* must be last test as channel hooks can't be unregistered */
4694 test_channel_hook();
4695
4696 CoUninitialize();
4697 }
4698