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
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) \
39 ok(called_ ## func, "expected " #func "\n"); \
40 expect_ ## func = called_ ## func = FALSE; \
43 #define CHECK_EXPECT2(func) \
45 ok(expect_ ##func, "unexpected call " #func "\n"); \
46 called_ ## func = TRUE; \
49 #define CHECK_CALLED_BROKEN(func) \
51 ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \
52 expect_ ## func = called_ ## func = FALSE; \
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
)
65 rc
= IUnknown_Release(obj
);
66 ok_(__FILE__
,line
)(rc
== ref
, "expected refcount %d, got %d\n", ref
, rc
);
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
))
90 ok(0, "Unknown interface %s\n", wine_dbgstr_guid(riid
));
94 static ULONG WINAPI
driver_AddRef(IDispenserDriver
*iface
)
99 static ULONG WINAPI
driver_Release(IDispenserDriver
*iface
)
101 CHECK_EXPECT2(driver_Release
);
105 static HRESULT WINAPI
driver_CreateResource(IDispenserDriver
*iface
, const RESTYPID restypid
, RESID
*resid
, TIMEINSECS
*destroy
)
107 CHECK_EXPECT2(driver_CreateResource
);
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");
120 static HRESULT WINAPI
driver_EnlistResource(IDispenserDriver
*iface
, const RESID resid
, const TRANSID transid
)
122 ok(0, "unexpected call\n");
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
);
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");
147 static const struct IDispenserDriverVtbl driver_vtbl
=
149 driver_QueryInterface
,
152 driver_CreateResource
,
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
)
171 hr
= CoCreateInstance(&CLSID_XMLDocument
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void **)&unk
);
172 if (hr
== S_OK
) IUnknown_Release(unk
);
177 static void create_dispenser(void)
180 IDispenserManager
*dispenser
= NULL
;
181 IHolder
*holder1
= NULL
, *holder2
= NULL
, *holder3
= NULL
;
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
);
192 win_skip("DispenserManager not available\n");
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
);
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. */
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
);
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
);
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
);
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
);
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
);
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
);
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;
303 hr
= IMoniker_GetSizeMax(moniker
, NULL
);
304 ok(hr
== E_POINTER
, "Unexpected hr %#x.\n", hr
);
306 expected_size
= sizeof(GUID
) + 2 * sizeof(DWORD
);
309 progid_len
= lstrlenW(progid
) * sizeof(*progid
);
310 expected_size
+= progid_len
;
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
),
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:
340 WCHAR progid[progid_len/2];
346 ok(*ptr
== progid_len
, "Unexpected progid length.\n");
348 ok(!memcmp(ptr
, progid
, progid_len
), "Unexpected progid.\n");
349 ptr
+= progid_len
/ sizeof(DWORD
);
353 ok(*ptr
== 0, "Unexpected progid length.\n");
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
;
378 hr
= CreateBindCtx(0, &bindctx
);
379 ok(hr
== S_OK
, "Failed to create bind context, hr %#x.\n", hr
);
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
);
391 hr
= IMoniker_ParseDisplayName(moniker
, bindctx
, NULL
, (WCHAR
*)L
"new:20d04fe0-3aea-1069-a2d8-08002b30309d",
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
);
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
);
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
);
457 ok(hr
== S_FALSE
, "Unexpected hr %#x.\n", hr
);
459 hr
= IMoniker_IsRunning(moniker
, bindctx
, NULL
, NULL
);
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
);
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");
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
);
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
);
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
);
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
);
539 ok(hr
== MK_E_UNAVAILABLE
, "Unexpected hr %#x.\n", hr
);
541 IRunningObjectTable_Release(rot
);
543 IUnknown_Release(obj
);
545 IBindCtx_Release(bindctx
);
552 hr
= CoInitialize(0);
553 ok( hr
== S_OK
, "failed to init com\n");