ReactOS  0.4.14-dev-608-gd495a4f
marshal.c
Go to the documentation of this file.
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];
86 
87 typedef UINT64 OXID;
88 typedef UINT64 OID;
89 typedef GUID IPID;
90 
91 typedef struct tagSTDOBJREF {
97 } STDOBJREF;
98 
99 typedef struct tagOBJREF {
103  union {
104  struct OR_STANDARD {
107  } u_standard;
108  struct OR_HANDLER {
109  STDOBJREF std;
112  } u_handler;
113  struct OR_CUSTOM {
114  CLSID clsid;
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 
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);
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 
171 static void LockModule(void)
172 {
174 }
175 
176 static void UnlockModule(void)
177 {
179 }
180 
184 
186 {
187  ok(0, "unexpected call\n");
188  *ppv = NULL;
189  return E_NOINTERFACE;
190 }
191 
193 {
194  return 2;
195 }
196 
198 {
199  return 1;
200 }
201 
203 {
204  trace("add connection\n");
205  return ++external_connections;
206 }
207 
208 
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 = {
223 };
224 
226 
227 
229  LPUNKNOWN iface,
230  REFIID riid,
231  LPVOID *ppvObj)
232 {
233  if (ppvObj == NULL) return E_POINTER;
234 
236  {
237  *ppvObj = iface;
238  IUnknown_AddRef(iface);
239  return S_OK;
240  }
241 
242  *ppvObj = NULL;
243  return E_NOINTERFACE;
244 }
245 
247 {
248  LockModule();
249  return 2; /* non-heap-based object */
250 }
251 
253 {
254  UnlockModule();
255  return 1; /* non-heap-based object */
256 }
257 
258 static const IUnknownVtbl TestUnknown_Vtbl =
259 {
263 };
264 
266 
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 {
282 };
283 
285 
287  LPCLASSFACTORY iface,
288  REFIID riid,
289  LPVOID *ppvObj)
290 {
291  if (ppvObj == NULL) return E_POINTER;
292 
293  if (IsEqualGUID(riid, &IID_IUnknown) ||
295  /* the only other interface Wine is currently able to marshal (for testing two proxies) */
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 
313 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
314 {
315  LockModule();
316  return 2; /* non-heap-based object */
317 }
318 
319 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
320 {
321  UnlockModule();
322  return 1; /* non-heap-based object */
323 }
324 
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 
336  LPCLASSFACTORY iface,
337  BOOL fLock)
338 {
339  return S_OK;
340 }
341 
342 static const IClassFactoryVtbl TestClassFactory_Vtbl =
343 {
349 };
350 
352 
353 DEFINE_EXPECT(Invoke);
354 DEFINE_EXPECT(CreateStub);
355 DEFINE_EXPECT(CreateProxy);
357 DEFINE_EXPECT(Disconnect);
358 
360 {
361  ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
362  *ppv = NULL;
363  return E_NOINTERFACE;
364 }
365 
367 {
368  return 2;
369 }
370 
372 {
373  return 1;
374 }
375 
377 {
379  *hwnd = (HWND)0xdeadbeef;
380  return S_OK;
381 }
382 
383 static const IOleWindowVtbl OleWindowVtbl = {
388  /* not needed */
389 };
390 
392 
394 {
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 
410 {
411  return 2;
412 }
413 
415 {
416  return 1;
417 }
418 
419 static const IOleClientSiteVtbl OleClientSiteVtbl = {
423  /* we don't need the rest, we never call it */
424 };
425 
427 
428 typedef struct {
433 
435 {
436  return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface);
437 }
438 
440 {
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 
455 {
457  return InterlockedIncrement(&This->ref);
458 }
459 
461 {
464  if(!ref) {
465  IRpcStubBuffer_Release(This->buffer);
466  heap_free(This);
467  }
468  return ref;
469 }
470 
472 {
473  ok(0, "unexpected call\n");
474  return E_NOTIMPL;
475 }
476 
478 {
479  CHECK_EXPECT(Disconnect);
480 }
481 
482 static HRESULT WINAPI RpcStubBuffer_Invoke(IRpcStubBuffer *iface, RPCOLEMESSAGE *_prpcmsg,
483  IRpcChannelBuffer *_pRpcChannelBuffer)
484 {
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 
501 {
502  ok(0, "unexpected call\n");
503  return NULL;
504 }
505 
507 {
508  ok(0, "unexpected call\n");
509  return E_NOTIMPL;
510 }
511 
513 {
514  ok(0, "unexpected call\n");
515  return E_NOTIMPL;
516 }
517 
519 {
520  ok(0, "unexpected call\n");
521 }
522 
523 static const IRpcStubBufferVtbl RpcStubBufferVtbl = {
534 };
535 
537 
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 
552 {
553  return 2;
554 }
555 
557 {
558  return 1;
559 }
560 
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 
569  IUnknown *server, IRpcStubBuffer **ppStub)
570 {
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 {
596 };
597 
599 
600 #define RELEASEMARSHALDATA WM_USER
601 
603 {
605  const IID *iid;
607  MSHLFLAGS marshal_flags;
612 };
613 
614 #ifndef __REACTOS__ /* FIXME: Inspect */
616 #endif
617 
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, &registration_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);
639  }
640 
641  hr = CoMarshalInterface(data->stream, data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
643 
644  /* force the message queue to be created before signaling parent thread */
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
658  }
659 
661 
662  CoUninitialize();
663 
664  return hr;
665 }
666 
668 {
669  DWORD tid = 0;
670  struct host_object_data *data;
671 
672  data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
673  *data = *object_data;
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 
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. */
693 {
694  HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
696  ok( !WaitForSingleObject(event, 10000), "wait timed out\n" );
698 }
699 
701 {
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" );
707 }
708 
709 /* tests failure case of interface not having a marshaler specified in the
710  * registry */
711 static void test_no_marshaler(void)
712 {
713  IStream *pStream;
714  HRESULT hr;
715 
716  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
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 */
726 {
727  HRESULT hr;
728  IStream *pStream = NULL;
729 
730  cLocks = 0;
732 
733  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
735  hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
737 
740 
741  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
742  hr = CoReleaseMarshalData(pStream);
744  IStream_Release(pStream);
745 
746  ok_no_locks();
749 }
750 
751 /* tests success case of a same-thread marshal and unmarshal */
753 {
754  HRESULT hr;
755  IStream *pStream = NULL;
756  IUnknown *pProxy = NULL;
757 
758  cLocks = 0;
760 
761  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
763  hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
765 
768 
769  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
770  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
772  IStream_Release(pStream);
773 
777 
778  IUnknown_Release(pProxy);
779 
780  ok_no_locks();
781 }
782 
783 /* tests failure case of unmarshaling a freed object */
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;
795 
796  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
798  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
799 
802 
803  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
804  hr = CoReleaseMarshalData(pStream);
806 
807  ok_no_locks();
810 
811  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
812  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
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 
828 }
829 
831 {
832  HRESULT hr;
833  IStream *pStream;
834  IUnknown *pProxy;
835  static const LARGE_INTEGER llZero;
836 
837  cLocks = 0;
839 
840  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
842 
843  hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
845 
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();
858 
859  IStream_Release(pStream);
860 }
861 
862 /* tests success case of an interthread marshal */
864 {
865  HRESULT hr;
866  IStream *pStream = NULL;
867  IUnknown *pProxy = NULL;
868  DWORD tid;
869  HANDLE thread;
870 
871  cLocks = 0;
873 
874  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
876  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
877 
880 
881  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
882  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
884  IStream_Release(pStream);
885 
888 
889  IUnknown_Release(pProxy);
890 
891  ok_no_locks();
894 
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 */
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;
915 
916  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
918  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
919 
922 
923  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
924  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
926 
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);
933 
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);
941  }
942 
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);
952 
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);
963 
964  IUnknown_Release(pProxy2);
965  }
966 
967  ok_no_locks();
970 
971  IStream_Release(pStream);
972 
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 */
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;
989 
990  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
992  tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
993 
996 
997  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
998  hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1000 
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);
1007 
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);
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 
1026 
1027  IUnknown_Release(pProxy);
1028 
1031 
1032  IUnknown_Release(pProxy2);
1033 
1034  ok_no_locks();
1037 
1039 }
1040 
1041 /* tests success case of an interthread marshal and then table-weak-marshaling the proxy */
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;
1053 
1054  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1056  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1057 
1060 
1061  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1062  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1064 
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);
1072 
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();
1088 
1089  IStream_Release(pStream);
1090 
1092 }
1093 
1094 /* tests success case of an interthread marshal and then table-strong-marshaling the proxy */
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;
1106 
1107  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1109  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1110 
1113 
1114  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1115  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1117 
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 
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);
1142 
1145 
1146  IUnknown_Release(pProxy2);
1147 
1150 
1151 end:
1152  IStream_Release(pStream);
1153 
1155 
1156  ok_no_locks();
1157 todo_wine {
1160 }
1161 }
1162 
1163 /* tests that stubs are released when the containing apartment is destroyed */
1165 {
1166  HRESULT hr;
1167  IStream *pStream = NULL;
1168  IUnknown *pProxy = NULL;
1169  DWORD tid;
1170  HANDLE thread;
1171 
1172  cLocks = 0;
1174 
1175  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1177  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1178 
1181 
1182  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1183  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1185  IStream_Release(pStream);
1186 
1189 
1191 
1192  ok_no_locks();
1193 todo_wine {
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 */
1205 {
1206  HRESULT hr;
1207  IStream *pStream = NULL;
1209  IUnknown *unk;
1210  ULONG ref;
1211  DWORD tid;
1212  HANDLE thread;
1213 
1214  cLocks = 0;
1216 
1217  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1219  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1220 
1223 
1224  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1225  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1227  IStream_Release(pStream);
1228 
1231 
1232  CoUninitialize();
1233 
1234  ok_no_locks();
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 
1247 
1248  pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1249 }
1250 
1251 /* tests that proxies are released when the containing mta apartment is destroyed */
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;
1265 
1266  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1268  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1269 
1272 
1273  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1274  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1276  IStream_Release(pStream);
1277 
1280 
1281  CoUninitialize();
1282 
1283  ok_no_locks();
1286 
1287  IUnknown_Release(pProxy);
1288 
1289  ok_no_locks();
1290 
1292 
1293  pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1294 }
1295 
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 
1308  MSHLFLAGS_NORMAL, NULL, (IUnknown*)&PSFactoryBuffer,
1310 
1311  cLocks = 0;
1313 
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);
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);
1328  IStream_Release(object_data.stream);
1329 
1331  CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &registration_key);
1332  ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
1333 
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);
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);
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 
1363 }
1364 
1365 static const CLSID *unmarshal_class;
1369 
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 
1385 {
1386  return 2;
1387 }
1388 
1390 {
1391  return 1;
1392 }
1393 
1395  void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
1396 {
1398  *clsid = *unmarshal_class;
1399  return S_OK;
1400 }
1401 
1403  void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *size)
1404 {
1406  ok(size != NULL, "size = NULL\n");
1407 
1408  *size = 0;
1409  return S_OK;
1410 }
1411 
1413  REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
1414 {
1415  IMarshal *std_marshal;
1416  STATSTG stat;
1417  HRESULT hr;
1418 
1420 
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);
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 
1441  IStream *stream, REFIID riid, void **ppv)
1442 {
1443  ok(0, "unexpected call\n");
1444  return E_NOTIMPL;
1445 }
1446 
1448 {
1449  ok(0, "unexpected call\n");
1450  return E_NOTIMPL;
1451 }
1452 
1454 {
1455  ok(0, "unexpected call\n");
1456  return E_NOTIMPL;
1457 }
1458 
1459 static IMarshalVtbl CustomMarshalVtbl =
1460 {
1470 };
1471 
1473 
1475 {
1476  IStream *stream;
1477  IUnknown *unk;
1478  DWORD size;
1479  HRESULT hr;
1480 
1483 
1488  MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
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);
1497  ok(unk == (IUnknown*)&CustomMarshal, "unk != &CustomMarshal\n");
1498  IUnknown_Release(unk);
1499  IStream_Release(stream);
1500 
1503 
1507  MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1511 
1512  hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1513  ok_ole_success(hr, IStream_Seek);
1516  IStream_Release(stream);
1517 
1520  MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1523  ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1524 }
1525 
1527 {
1528  DWORD size, read;
1529  IStream *stream;
1530  OBJREF objref;
1531  HRESULT hr;
1532 
1535 
1541  MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
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 
1569  MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1572  ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1573 }
1574 
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 
1589 
1591  MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &marshal);
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);
1603  MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
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 }
1653 {
1657 };
1658 
1659 /* helper for test_no_couninitialize_server */
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);
1669 
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 */
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;
1692 
1695 
1696  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1698  ncu_params.stream = pStream;
1699 
1701 
1702  ok( !WaitForSingleObject(ncu_params.marshal_event, 10000), "wait timed out\n" );
1705 
1706  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1707  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1709  IStream_Release(pStream);
1710 
1713 
1715  ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1716 
1717  ok_no_locks();
1718 todo_wine {
1721 }
1722 
1726 
1727  IUnknown_Release(pProxy);
1728 
1729  ok_no_locks();
1730 }
1731 
1732 /* STA -> STA call during DLL_THREAD_DETACH */
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);
1743  IStream_Release(ncu_params->stream);
1744 
1746 
1747  /* die without calling CoUninitialize */
1748 
1749  return 0;
1750 }
1751 
1752 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
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;
1765 
1766  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
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 
1777 
1779 
1780  ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1782 
1783  ok_no_locks();
1786 
1787  end_host_object(host_tid, host_thread);
1788 }
1789 
1791 
1793 {
1794  IStream *stream;
1795  HRESULT hr;
1796 
1797  cLocks = 0;
1798 
1799  CoInitialize(NULL);
1800 
1803 
1804  hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1806 
1807  IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1808 
1811 
1812  ok_no_locks();
1813 
1814  hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1816 
1818 
1819  trace("CoUninitialize >>>\n");
1820  CoUninitialize();
1821  trace("CoUninitialize <<<\n");
1822 
1823  ok_no_locks();
1824 
1825  IStream_Release(stream);
1827  return 0;
1828 }
1829 
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 
1842  ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1844  ok(crash_thread_success, "Crash thread failed\n");
1845 }
1846 
1847 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
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;
1859 
1860  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1862  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1863 
1866 
1867  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1868  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1870 
1873 
1874  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1875  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1877 
1879 
1880  IUnknown_Release(pProxy1);
1882  IUnknown_Release(pProxy2);
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  {
1891  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
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);
1901 }
1902 
1903 /* tests releasing after unmarshaling one object */
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;
1915 
1916  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1918  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1919 
1922 
1923  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1924  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1926 
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);
1934 
1937 
1938  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1939  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1941  IStream_Release(pStream);
1942 
1945 
1946  IUnknown_Release(pProxy1);
1947 
1948  if (pProxy2)
1949  {
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();
1960 
1962 }
1963 
1964 /* tests releasing after unmarshaling one object */
1966 {
1967  HRESULT hr;
1968  IStream *pStream = NULL;
1969  IUnknown *pProxy = NULL;
1970  DWORD tid;
1971  HANDLE thread;
1972 
1973  cLocks = 0;
1975 
1976  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1978  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1979 
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);
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();
2002 
2004 }
2005 
2007 {
2012 };
2013 
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 */
2031 
2032  SetEvent(data->hReadyEvent);
2033 
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
2045  }
2046  }
2048 
2049  CoUninitialize();
2050 
2051  return 0;
2052 }
2053 
2054 /* tests interaction between table-weak and normal marshalling of an object */
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;
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);
2073  hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2075 
2077  ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2078  CloseHandle(data.hReadyEvent);
2079 
2082 
2083  /* weak */
2084  IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2085  hr = CoUnmarshalInterface(data.pStream1, &IID_IClassFactory, (void **)&pProxyWeak);
2087 
2089 
2090  /* normal */
2091  IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2092  hr = CoUnmarshalInterface(data.pStream2, &IID_IClassFactory, (void **)&pProxyNormal);
2094 
2096 
2097  IUnknown_Release(pProxyNormal);
2098 
2101 
2102  IUnknown_Release(pProxyWeak);
2103 
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  {
2112  IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
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" );
2123 }
2124 
2126 {
2127  HRESULT hr;
2128  DWORD tid;
2129  HANDLE thread;
2130  struct duo_marshal_data data;
2131 
2132  cLocks = 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);
2141  hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2143 
2145  ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2146  CloseHandle(data.hReadyEvent);
2147 
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);
2154 
2157 
2158  if (with_external_conn)
2159  {
2161  IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
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" );
2173 }
2174 
2176 {
2177  HRESULT hr;
2178  DWORD tid;
2179  HANDLE thread;
2180  struct duo_marshal_data data;
2181 
2182  cLocks = 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);
2191  hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2193 
2195  ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2196  CloseHandle(data.hReadyEvent);
2197 
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);
2204 
2206 
2207  IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
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" );
2218 }
2219 
2220 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
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;
2232 
2233  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2235  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
2236 
2239 
2240  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2241  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2243 
2245 
2246  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2247  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2249 
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 */
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);
2264  IStream_Release(pStream);
2265 
2266  ok_no_locks();
2269 
2271 }
2272 
2273 /* tests CoLockObjectExternal */
2274 static void test_lock_object_external(void)
2275 {
2276  HRESULT hr;
2277  IStream *pStream = NULL;
2278 
2279  cLocks = 0;
2281 
2282  /* test the stub manager creation aspect of CoLockObjectExternal when the
2283  * object hasn't been marshaled yet */
2285 
2288 
2290 
2291  ok_no_locks();
2294 
2295  /* test our empty stub manager being handled correctly in
2296  * CoMarshalInterface */
2298 
2299  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2301  hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2303 
2305 
2308 
2309  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2310  hr = CoReleaseMarshalData(pStream);
2312  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2313 
2317 
2319 
2323 
2325 
2326  ok_no_locks();
2329 
2330  /* test CoLockObjectExternal releases reference to object with
2331  * fLastUnlockReleases as TRUE and there are only strong references on
2332  * the object */
2334 
2337 
2339 
2340  ok_no_locks();
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);
2349 
2352 
2354 
2357 
2359 
2363 
2365 
2366  ok_no_locks();
2367 
2368  IStream_Release(pStream);
2369 }
2370 
2371 /* tests disconnecting stubs */
2372 static void test_disconnect_stub(void)
2373 {
2374  HRESULT hr;
2375  IStream *pStream = NULL;
2376 
2377  cLocks = 0;
2379 
2380  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2382  hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2384 
2386 
2388 
2391 
2392  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2393  hr = CoReleaseMarshalData(pStream);
2395  IStream_Release(pStream);
2396 
2399 
2401 
2402  ok_no_locks();
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 */
2411 {
2412  HRESULT hr;
2413  IStream *pStream = NULL;
2414  IUnknown *pProxy1 = NULL;
2415  IUnknown *pProxy2 = NULL;
2416 
2417  cLocks = 0;
2419 
2420  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2422  hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2424 
2427 
2428  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2429  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2431 
2435 
2436  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2437  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
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 
2444 
2445  IUnknown_Release(pProxy1);
2446 
2447  ok_no_locks();
2448 }
2449 
2450 /* tests success case of marshaling and unmarshaling an HRESULT */
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);
2460 
2461  hr = CoMarshalHresult(pStream, E_DEADBEEF);
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);
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 */
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
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);
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 */
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);
2540  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
2541 
2543 
2544  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2545  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
2547  IStream_Release(pStream);
2548 
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" );
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 
2570 {
2571  if (ppvObj == NULL) return E_POINTER;
2572 
2573  if (IsEqualGUID(riid, &IID_IUnknown) ||
2575  {
2576  *ppvObj = iface;
2577  IMessageFilter_AddRef(iface);
2578  return S_OK;
2579  }
2580 
2581  return E_NOINTERFACE;
2582 }
2583 
2585 {
2586  return 2; /* non-heap object */
2587 }
2588 
2590 {
2591  return 1; /* non-heap object */
2592 }
2593 
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 
2621  IMessageFilter *iface,
2622  HTASK threadIDCallee,
2623  DWORD dwTickCount,
2624  DWORD dwRejectType)
2625 {
2626  trace("RetryRejectedCall\n");
2627  return 0;
2628 }
2629 
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 {
2648 };
2649 
2651 
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);
2668  tid = start_host_object2(&object_data, &thread);
2669 
2671 
2672  IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
2673  hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
2675  IStream_Release(object_data.stream);
2676 
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);
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 
2697 
2698  hr = CoRegisterMessageFilter(prev_filter, NULL);
2700 }
2701 
2702 /* test failure case of trying to unmarshal from bad stream */
2703 static void test_bad_marshal_stream(void)
2704 {
2705  HRESULT hr;
2706  IStream *pStream = NULL;
2707 
2708  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2710  hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2712 
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);
2723 
2724  IStream_Release(pStream);
2725 }
2726 
2727 /* tests that proxies implement certain interfaces */
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);
2741  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2742 
2744 
2745  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2746  hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
2748  IStream_Release(pStream);
2749 
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 
2776 }
2777 
2778 typedef struct
2779 {
2782 } HeapUnknown;
2783 
2785 {
2786  return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
2787 }
2788 
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 
2802 {
2804  return InterlockedIncrement((LONG*)&This->refs);
2805 }
2806 
2808 {
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 {
2820 };
2821 
2823 {
2824  HRESULT hr;
2825  IPSFactoryBuffer *psfb;
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);
2837 
2838  hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
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 
2861 {
2862  HRESULT hr;
2863  IPSFactoryBuffer *psfb;
2865  ULONG refs;
2866  CLSID clsid;
2867 
2868  cLocks = 0;
2869 
2870  hr = CoGetPSClsid(riid, &clsid);
2872 
2873  hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
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 
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 
2893 
2895  LPCLASSFACTORY iface,
2896  LPUNKNOWN pUnkOuter,
2897  REFIID riid,
2898  LPVOID *ppvObj)
2899 {
2900  DWORD_PTR res;
2901  if (IsEqualIID(riid, &IID_IWineTest))
2902  {
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 {
2917 };
2918 
2920 
2922 {
2923  switch (msg)
2924  {
2925  case WM_USER:
2926  {
2927  HRESULT hr;
2928  IStream *pStream = NULL;
2930  IUnknown *object;
2931  DWORD tid;
2932  HANDLE thread;
2933 
2934  cLocks = 0;
2935 
2936  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2938  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2939 
2941 
2942  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2943  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2945  IStream_Release(pStream);
2946 
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 
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;
2969  IUnknown *object;
2970  DWORD tid;
2971  HANDLE thread;
2972 
2973  cLocks = 0;
2974 
2975  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2977  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2978 
2980 
2981  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2982  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2984  IStream_Release(pStream);
2985 
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 
2999 
3000  return 0;
3001  }
3002  case WM_USER+2:
3003  {
3004  HRESULT hr;
3005  IStream *pStream = NULL;
3007  IUnknown *object;
3008  DWORD tid;
3009  HANDLE thread;
3010 
3011  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
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);
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);
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 
3029 
3030  PostQuitMessage(0);
3031 
3032  return 0;
3033  }
3034  default:
3035  return DefWindowProcA(hwnd, msg, wparam, lparam);
3036  }
3037 }
3038 
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 
3049 static void test_message_reentrancy(void)
3050 {
3051  MSG msg;
3052 
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  {
3063  }
3065 }
3066 
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 {
3085 };
3086 
3088 
3089 static void test_call_from_message(void)
3090 {
3091  MSG msg;
3092  IStream *pStream;
3093  HRESULT hr;
3095  DWORD tid;
3096  HANDLE thread;
3097  IUnknown *object;
3098 
3100  ok(hwnd_app != NULL, "Window creation failed\n");
3101 
3102  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3104  tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestMsg_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3105 
3107 
3108  IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3109  hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
3111  IStream_Release(pStream);
3112 
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 
3124 
3125  while (GetMessageA(&msg, NULL, 0, 0))
3126  {
3129  }
3131 }
3132 
3133 static void test_WM_QUIT_handling(void)
3134 {
3135  MSG msg;
3136 
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  {
3147  }
3148 }
3149 
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 
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);
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 
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);
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);
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",
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 
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 
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 
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 
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 
3308 
3309  /* this call shows that DisconnectObject does nothing */
3310  hr = IMarshal_DisconnectObject(pFTMarshal, 0);
3311  ok_ole_success(hr, IMarshal_DisconnectObject);
3312 
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",
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 
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);
3348 
3349  ok_no_locks();
3350 
3351  IStream_Release(pStream);
3352  IMarshal_Release(pFTMarshal);
3353 }
3354 
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  {
3388  *strrchr(buffer, '\\') = '\0';
3390  }
3391  return hr;
3392 }
3393 
3394 static void test_inproc_handler(void)
3395 {
3396  HRESULT hr;
3397  IUnknown *pObject;
3398  IUnknown *pObject2;
3399 
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 
3420 }
3421 
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 
3441 {
3442  LockModule();
3443  return 2; /* non-heap-based object */
3444 }
3445 
3447 {
3448  UnlockModule();
3449  return 1; /* non-heap-based object */
3450 }
3451 
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 {
3468 };
3469 
3471 
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 
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 
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  {
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 
3517 
3518  /* FIXME: test IPersist interface has the same effect as IStdMarshalInfo */
3519 }
3520 
3521 
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 
3608 }
3609 
3611 
3612 static void LockModuleOOP(void)
3613 {
3614  InterlockedIncrement(&cLocks); /* for test purposes only */
3616 }
3617 
3618 static void UnlockModuleOOP(void)
3619 {
3620  InterlockedDecrement(&cLocks); /* for test purposes only */
3621  if (!CoReleaseServerProcess())
3623 }
3624 
3625 static HWND hwnd_app;
3626 
3628 {
3629  IPersist IPersist_iface; /* a nice short interface */
3630 };
3631 
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 
3649 {
3650  return 2;
3651 }
3652 
3654 {
3655  return 1;
3656 }
3657 
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 {
3683 };
3684 
3686 {
3688 };
3689 
3691  LPCLASSFACTORY iface,
3692  REFIID riid,
3693  LPVOID *ppvObj)
3694 {
3695  if (ppvObj == NULL) return E_POINTER;
3696 
3697  if (IsEqualGUID(riid, &IID_IUnknown) ||
3699  {
3700  *ppvObj = iface;
3701  IClassFactory_AddRef(iface);
3702  return S_OK;
3703  }
3704 
3705  return E_NOINTERFACE;
3706 }
3707 
3708 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
3709 {
3710  return 2; /* non-heap-based object */
3711 }
3712 
3713 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
3714 {
3715  return 1; /* non-heap-based object */
3716 }
3717 
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 
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 {
3750 };
3751 
3753 
3755 {
3756  DWORD cookie;
3757  HRESULT hr;
3758  HANDLE ready_event;
3759  DWORD wait;
3760  HANDLE handles[2];
3761 
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:
3769  CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
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);
3786  }
3787  }
3788  else if (wait == WAIT_OBJECT_0+1)
3789  {
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" );
3800  CloseHandle(handles[0]);
3801  CloseHandle(handles[1]);
3802 }
3803 
3804 static HANDLE create_target_process(const char *arg)
3805 {
3806  char **argv;
3807  char cmdline[MAX_PATH];
3808  BOOL ret;
3810  STARTUPINFOA si = { 0 };
3811  si.cb = sizeof(si);
3812 
3813  pi.hThread = NULL;
3814  pi.hProcess = NULL;
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 */
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 
3838 
3839  cLocks = 0;
3840 
3841  /* Start the object suspended */
3843  CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
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,
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 ... */
3857 
3858  /* ... and now it should succeed */
3859  hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
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 
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 */
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 
3894 
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);
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);
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 
3930  CloseHandle(quit_event);
3932 }
3933 
3935 {
3938 };
3939 
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 
3967 static void