mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / comsvcs / tests / comsvcs.c
blobf0cf0d8543f21fe4870f3e084f5aef3688b3e2c2
1 /*
2 * Copyright 2018 Alistair Leslie-Hughes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "ole2.h"
26 #include "comsvcs.h"
27 #include "msxml.h"
29 #include "wine/test.h"
31 #define DEFINE_EXPECT(func) \
32 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
34 #define SET_EXPECT(func) \
35 expect_ ## func = TRUE
37 #define CHECK_CALLED(func) \
38 do { \
39 ok(called_ ## func, "expected " #func "\n"); \
40 expect_ ## func = called_ ## func = FALSE; \
41 }while(0)
43 #define CHECK_EXPECT2(func) \
44 do { \
45 ok(expect_ ##func, "unexpected call " #func "\n"); \
46 called_ ## func = TRUE; \
47 }while(0)
49 #define CHECK_CALLED_BROKEN(func) \
50 do { \
51 ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \
52 expect_ ## func = called_ ## func = FALSE; \
53 }while(0)
55 DEFINE_EXPECT(driver_CreateResource);
56 DEFINE_EXPECT(driver_DestroyResource);
57 DEFINE_EXPECT(driver_ResetResource);
58 DEFINE_EXPECT(driver_Release);
60 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
61 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
63 ULONG rc;
64 IUnknown_AddRef(obj);
65 rc = IUnknown_Release(obj);
66 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
69 struct test_driver
71 IDispenserDriver IDispenserDriver_iface;
72 HRESULT destroy_resource_hr;
75 static struct test_driver *impl_from_IDispenserDriver(IDispenserDriver *iface)
77 return CONTAINING_RECORD(iface, struct test_driver, IDispenserDriver_iface);
80 static HRESULT WINAPI driver_QueryInterface(IDispenserDriver *iface, REFIID riid, void **object)
82 if (IsEqualGUID(riid, &IID_IUnknown) ||
83 IsEqualGUID(riid, &IID_IDispenserDriver))
85 *object = iface;
87 return S_OK;
90 ok(0, "Unknown interface %s\n", wine_dbgstr_guid(riid));
91 return E_NOINTERFACE;
94 static ULONG WINAPI driver_AddRef(IDispenserDriver *iface)
96 return 2;
99 static ULONG WINAPI driver_Release(IDispenserDriver *iface)
101 CHECK_EXPECT2(driver_Release);
102 return 1;
105 static HRESULT WINAPI driver_CreateResource(IDispenserDriver *iface, const RESTYPID restypid, RESID *resid, TIMEINSECS *destroy)
107 CHECK_EXPECT2(driver_CreateResource);
109 *resid = 10;
110 return S_OK;
113 static HRESULT WINAPI driver_RateResource(IDispenserDriver *iface, const RESTYPID restypid, const RESID resid,
114 const BOOL requires, RESOURCERATING *rating)
116 ok(0, "unexpected call\n");
117 return E_NOTIMPL;
120 static HRESULT WINAPI driver_EnlistResource(IDispenserDriver *iface, const RESID resid, const TRANSID transid)
122 ok(0, "unexpected call\n");
123 return E_NOTIMPL;
126 static HRESULT WINAPI driver_ResetResource(IDispenserDriver *iface, const RESID resid)
128 CHECK_EXPECT2(driver_ResetResource);
129 ok((int)resid == 10, "RESID %d\n", (int)resid);
130 return S_OK;
133 static HRESULT WINAPI driver_DestroyResource(IDispenserDriver *iface, const RESID resid)
135 struct test_driver *driver = impl_from_IDispenserDriver(iface);
136 todo_wine CHECK_EXPECT2(driver_DestroyResource);
137 return driver->destroy_resource_hr;
140 static HRESULT WINAPI driver_DestroyResourceS(IDispenserDriver *iface, const SRESID resid)
142 ok(0, "unexpected call\n");
143 return E_NOTIMPL;
147 static const struct IDispenserDriverVtbl driver_vtbl =
149 driver_QueryInterface,
150 driver_AddRef,
151 driver_Release,
152 driver_CreateResource,
153 driver_RateResource,
154 driver_EnlistResource,
155 driver_ResetResource,
156 driver_DestroyResource,
157 driver_DestroyResourceS
160 static void init_test_driver(struct test_driver *driver)
162 driver->IDispenserDriver_iface.lpVtbl = &driver_vtbl;
163 driver->destroy_resource_hr = S_OK;
166 static DWORD WINAPI com_thread(void *arg)
168 IUnknown *unk;
169 HRESULT hr;
171 hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
172 if (hr == S_OK) IUnknown_Release(unk);
174 return hr;
177 static void create_dispenser(void)
179 HRESULT hr;
180 IDispenserManager *dispenser = NULL;
181 IHolder *holder1 = NULL, *holder2 = NULL, *holder3 = NULL;
182 HANDLE thread;
183 RESID resid;
184 DWORD ret;
185 BSTR str;
186 struct test_driver driver;
188 hr = CoCreateInstance( &CLSID_DispenserManager, NULL, CLSCTX_ALL, &IID_IDispenserManager, (void**)&dispenser);
189 ok(hr == S_OK, "Failed to create object 0x%08x\n", hr);
190 if(FAILED(hr))
192 win_skip("DispenserManager not available\n");
193 return;
196 thread = CreateThread(NULL, 0, com_thread, NULL, 0, NULL);
197 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
198 GetExitCodeThread(thread, &ret);
199 ok(ret == CO_E_NOTINITIALIZED, "got unexpected hr %#x\n", ret);
200 CloseHandle(thread);
202 init_test_driver(&driver);
204 hr = IDispenserManager_RegisterDispenser(dispenser, &driver.IDispenserDriver_iface, L"SC.Pool 0 0", &holder1);
205 ok(hr == S_OK, "got 0x%08x\n", hr);
207 /* The above call creates an MTA thread, but we need to wait for it to
208 * actually initialize. */
209 Sleep(200);
210 thread = CreateThread(NULL, 0, com_thread, NULL, 0, NULL);
211 ok(!WaitForSingleObject(thread, 20000), "wait failed\n");
212 GetExitCodeThread(thread, &ret);
213 ok(ret == S_OK, "got unexpected hr %#x\n", ret);
214 CloseHandle(thread);
216 hr = IDispenserManager_RegisterDispenser(dispenser, &driver.IDispenserDriver_iface, L"SC.Pool 0 0", &holder2);
217 ok(hr == S_OK, "got 0x%08x\n", hr);
218 ok(holder1 != holder2, "same holder object returned\n");
220 hr = IDispenserManager_RegisterDispenser(dispenser, &driver.IDispenserDriver_iface, L"SC.Pool 1 1", &holder3);
221 ok(hr == S_OK, "got 0x%08x\n", hr);
223 if(holder1)
225 SET_EXPECT(driver_CreateResource);
226 SET_EXPECT(driver_Release);
228 str = SysAllocString(L"data1");
229 hr = IHolder_AllocResource(holder1, (RESTYPID)str, &resid);
230 ok(hr == S_OK, "got 0x%08x\n", hr);
231 ok(resid == 10, "got %d\n", (int)resid);
232 SysFreeString(str);
234 CHECK_CALLED(driver_CreateResource);
235 todo_wine CHECK_CALLED_BROKEN(driver_Release);
237 SET_EXPECT(driver_ResetResource);
238 hr = IHolder_FreeResource(holder1, resid);
239 ok(hr == S_OK, "got 0x%08x\n", hr);
240 todo_wine CHECK_CALLED(driver_ResetResource);
242 SET_EXPECT(driver_DestroyResource);
243 SET_EXPECT(driver_Release);
244 hr = IHolder_Close(holder1);
245 ok(hr == S_OK, "got 0x%08x\n", hr);
246 CHECK_CALLED(driver_Release);
247 CHECK_CALLED(driver_DestroyResource);
249 IHolder_Release(holder1);
251 if(holder2)
253 SET_EXPECT(driver_CreateResource);
254 SET_EXPECT(driver_Release);
256 str = SysAllocString(L"data1");
257 hr = IHolder_AllocResource(holder2, (RESTYPID)str, &resid);
258 ok(hr == S_OK, "got 0x%08x\n", hr);
259 ok(resid == 10, "got %d\n", (int)resid);
260 SysFreeString(str);
262 CHECK_CALLED(driver_CreateResource);
263 todo_wine CHECK_CALLED_BROKEN(driver_Release);
265 SET_EXPECT(driver_ResetResource);
266 hr = IHolder_FreeResource(holder2, resid);
267 ok(hr == S_OK, "got 0x%08x\n", hr);
268 todo_wine CHECK_CALLED(driver_ResetResource);
270 /* DestroyResource return doesn't directly affect the Holder Close return value */
271 driver.destroy_resource_hr = E_FAIL;
272 SET_EXPECT(driver_DestroyResource);
273 SET_EXPECT(driver_Release);
274 hr = IHolder_Close(holder2);
275 ok(hr == S_OK, "got 0x%08x\n", hr);
276 CHECK_CALLED(driver_Release);
277 CHECK_CALLED(driver_DestroyResource);
278 driver.destroy_resource_hr = S_OK;
279 IHolder_Release(holder2);
281 if(holder3)
283 SET_EXPECT(driver_Release);
284 hr = IHolder_Close(holder3);
285 ok(hr == S_OK, "got 0x%08x\n", hr);
286 CHECK_CALLED(driver_Release);
287 IHolder_Release(holder3);
290 IDispenserManager_Release(dispenser);
293 static void test_new_moniker_serialize(const WCHAR *clsid, const WCHAR *progid, IMoniker *moniker)
295 DWORD expected_size, progid_len = 0;
296 ULARGE_INTEGER size;
297 IStream *stream;
298 HGLOBAL hglobal;
299 CLSID guid;
300 HRESULT hr;
301 DWORD *ptr;
303 hr = IMoniker_GetSizeMax(moniker, NULL);
304 ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
306 expected_size = sizeof(GUID) + 2 * sizeof(DWORD);
307 if (progid)
309 progid_len = lstrlenW(progid) * sizeof(*progid);
310 expected_size += progid_len;
313 size.QuadPart = 0;
314 hr = IMoniker_GetSizeMax(moniker, &size);
315 ok(hr == S_OK, "Failed to get size, hr %#x.\n", hr);
316 ok(size.QuadPart == expected_size, "Unexpected size %s, expected %#x.\n", wine_dbgstr_longlong(size.QuadPart),
317 expected_size);
319 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
320 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
322 hr = IMoniker_Save(moniker, stream, FALSE);
323 ok(hr == S_OK, "Failed to save moniker, hr %#x.\n", hr);
325 hr = GetHGlobalFromStream(stream, &hglobal);
326 ok(hr == S_OK, "Failed to get a handle, hr %#x.\n", hr);
328 ptr = GlobalLock(hglobal);
329 ok(!!ptr, "Failed to get data pointer.\n");
331 hr = CLSIDFromString(clsid, &guid);
332 ok(hr == S_OK, "Failed to get CLSID, hr %#x.\n", hr);
333 ok(IsEqualGUID((GUID *)ptr, &guid), "Unexpected buffer content.\n");
334 ptr += sizeof(GUID)/sizeof(DWORD);
336 /* Serialization format:
338 GUID guid;
339 DWORD progid_len;
340 WCHAR progid[progid_len/2];
341 DWORD null;
344 if (progid)
346 ok(*ptr == progid_len, "Unexpected progid length.\n");
347 ptr++;
348 ok(!memcmp(ptr, progid, progid_len), "Unexpected progid.\n");
349 ptr += progid_len / sizeof(DWORD);
351 else
353 ok(*ptr == 0, "Unexpected progid length.\n");
354 ptr++;
356 ok(*ptr == 0, "Unexpected terminator.\n");
358 GlobalUnlock(hglobal);
360 IStream_Release(stream);
363 static void test_new_moniker(void)
365 IMoniker *moniker, *moniker2, *inverse, *class_moniker, *moniker_left;
366 IRunningObjectTable *rot;
367 IUnknown *obj, *obj2;
368 BIND_OPTS2 bind_opts;
369 DWORD moniker_type;
370 IROTData *rot_data;
371 IBindCtx *bindctx;
372 FILETIME filetime;
373 DWORD hash, eaten;
374 CLSID clsid;
375 HRESULT hr;
376 WCHAR *str;
378 hr = CreateBindCtx(0, &bindctx);
379 ok(hr == S_OK, "Failed to create bind context, hr %#x.\n", hr);
381 eaten = 0;
382 hr = MkParseDisplayName(bindctx, L"new:20d04fe0-3aea-1069-a2d8-08002b30309d", &eaten, &moniker);
383 ok(hr == S_OK, "Failed to parse display name, hr %#x.\n", hr);
384 ok(eaten == 40, "Unexpected eaten length %u.\n", eaten);
386 hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rot_data);
387 ok(hr == S_OK, "Failed to get IROTData, hr %#x.\n", hr);
388 IROTData_Release(rot_data);
390 eaten = 0;
391 hr = IMoniker_ParseDisplayName(moniker, bindctx, NULL, (WCHAR *)L"new:20d04fe0-3aea-1069-a2d8-08002b30309d",
392 &eaten, &moniker2);
393 ok(hr == S_OK, "Failed to parse display name, hr %#x.\n", hr);
394 ok(eaten == 40, "Unexpected eaten length %u.\n", eaten);
395 IMoniker_Release(moniker2);
397 hr = IMoniker_QueryInterface(moniker, &IID_IParseDisplayName, (void **)&obj);
398 ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
400 /* Object creation. */
401 hr = CLSIDFromProgID(L"new", &clsid);
402 ok(hr == S_OK, "Failed to get clsid, hr %#x.\n", hr);
404 hr = CreateClassMoniker(&clsid, &class_moniker);
405 ok(hr == S_OK, "Failed to create class moniker, hr %#x.\n", hr);
407 hr = IMoniker_BindToObject(class_moniker, bindctx, NULL, &IID_IParseDisplayName, (void **)&obj);
408 ok(hr == S_OK, "Failed to get parsing interface, hr %#x.\n", hr);
409 IUnknown_Release(obj);
411 hr = IMoniker_BindToObject(class_moniker, bindctx, NULL, &IID_IClassFactory, (void **)&obj);
412 ok(hr == S_OK, "Failed to get parsing interface, hr %#x.\n", hr);
413 IUnknown_Release(obj);
415 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IParseDisplayName, (void **)&obj);
416 ok(hr == S_OK, "Failed to get parsing interface, hr %#x.\n", hr);
417 IUnknown_Release(obj);
419 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void **)&obj);
420 ok(hr == S_OK, "Failed to get parsing interface, hr %#x.\n", hr);
422 hr = IUnknown_QueryInterface(obj, &IID_IParseDisplayName, (void **)&obj2);
423 ok(hr == S_OK, "Failed to get parsing interface, hr %#x.\n", hr);
424 IUnknown_Release(obj);
426 IMoniker_Release(class_moniker);
428 /* Reducing. */
429 moniker_left = (void *)0xdeadbeef;
430 hr = IMoniker_Reduce(moniker, bindctx, MKRREDUCE_ONE, &moniker_left, &moniker2);
431 ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#x.\n", hr);
432 ok(moniker_left == (void *)0xdeadbeef, "Unexpected left moniker.\n");
433 ok(moniker2 == moniker, "Unexpected returned moniker.\n");
434 IMoniker_Release(moniker2);
436 hr = IMoniker_Reduce(moniker, bindctx, MKRREDUCE_ONE, NULL, &moniker2);
437 ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#x.\n", hr);
438 ok(moniker2 == moniker, "Unexpected returned moniker.\n");
439 IMoniker_Release(moniker2);
441 hr = IMoniker_Reduce(moniker, bindctx, MKRREDUCE_ONE, NULL, NULL);
442 ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
444 /* Hashing */
445 hash = 0;
446 hr = IMoniker_Hash(moniker, &hash);
447 ok(hr == S_OK, "Failed to get a hash, hr %#x.\n", hr);
448 ok(hash == 0x20d04fe0, "Unexpected hash value %#x.\n", hash);
450 moniker_type = MKSYS_CLASSMONIKER;
451 hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
452 ok(hr == S_FALSE || broken(hr == S_OK) /* XP */, "Unexpected hr %#x.\n", hr);
453 ok(moniker_type == MKSYS_NONE, "Unexpected moniker type %d.\n", moniker_type);
455 hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
456 todo_wine
457 ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
459 hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
460 todo_wine
461 ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
463 hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
464 ok(hr == MK_E_UNAVAILABLE, "Unexpected hr %#x.\n", hr);
466 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&obj);
467 ok(hr == S_OK, "Failed to bind to object, hr %#x.\n", hr);
468 IUnknown_Release(obj);
470 hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&obj);
471 todo_wine
472 ok(hr == MK_E_NOSTORAGE, "Unexpected hr %#x.\n", hr);
474 hr = IMoniker_Inverse(moniker, &inverse);
475 ok(hr == S_OK, "Failed to create inverse moniker, hr %#x.\n", hr);
476 moniker_type = MKSYS_NONE;
477 hr = IMoniker_IsSystemMoniker(inverse, &moniker_type);
478 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
479 ok(moniker_type == MKSYS_ANTIMONIKER, "Unexpected moniker type %d.\n", moniker_type);
480 IMoniker_Release(inverse);
482 hr = IMoniker_Enum(moniker, FALSE, NULL);
483 ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
485 obj = (IUnknown *)moniker;
486 hr = IMoniker_Enum(moniker, FALSE, (IEnumMoniker **)&obj);
487 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
488 ok(obj == NULL, "Unexpected return value.\n");
490 /* Serialization. */
491 test_new_moniker_serialize(L"{20d04fe0-3aea-1069-a2d8-08002b30309d}", NULL, moniker);
493 hr = IMoniker_IsDirty(moniker);
494 ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
496 hr = IMoniker_GetClassID(moniker, NULL);
497 ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
499 IMoniker_Release(moniker);
501 /* Full path to create new object, using progid. */
502 memset(&bind_opts, 0, sizeof(bind_opts));
503 bind_opts.cbStruct = sizeof(bind_opts);
504 bind_opts.dwClassContext = CLSCTX_INPROC_SERVER;
506 hr = CoGetObject(L"new:msxml2.domdocument", (BIND_OPTS *)&bind_opts, &IID_IXMLDOMDocument, (void **)&obj);
507 ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr);
508 IUnknown_Release(obj);
510 IBindCtx_Release(bindctx);
512 /* Returned object is not bound to context. */
513 hr = CreateBindCtx(0, &bindctx);
514 ok(hr == S_OK, "Failed to create bind context, hr %#x.\n", hr);
516 eaten = 0;
517 hr = MkParseDisplayName(bindctx, L"new:msxml2.domdocument", &eaten, &moniker);
518 ok(hr == S_OK, "Failed to parse display name, hr %#x.\n", hr);
519 ok(eaten, "Unexpected eaten length %u.\n", eaten);
521 hr = CLSIDFromProgID(L"msxml2.domdocument", &clsid);
522 ok(hr == S_OK, "Failed to get clsid, hr %#x.\n", hr);
524 hr = StringFromCLSID(&clsid, &str);
525 ok(hr == S_OK, "Failed to get guid string, hr %#x.\n", hr);
527 test_new_moniker_serialize(str, L"msxml2.domdocument", moniker);
528 CoTaskMemFree(str);
530 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&obj);
531 ok(hr == S_OK, "Failed to bind to object, hr %#x.\n", hr);
532 EXPECT_REF(obj, 1);
534 hr = IBindCtx_GetRunningObjectTable(bindctx, &rot);
535 ok(hr == S_OK, "Failed to get rot, hr %#x.\n", hr);
537 hr = IRunningObjectTable_GetObject(rot, moniker, &obj2);
538 todo_wine
539 ok(hr == MK_E_UNAVAILABLE, "Unexpected hr %#x.\n", hr);
541 IRunningObjectTable_Release(rot);
543 IUnknown_Release(obj);
545 IBindCtx_Release(bindctx);
548 START_TEST(comsvcs)
550 HRESULT hr;
552 hr = CoInitialize(0);
553 ok( hr == S_OK, "failed to init com\n");
554 if (hr != S_OK)
555 return;
557 create_dispenser();
558 test_new_moniker();
560 CoUninitialize();