1 /*
2  * Copyright 2010 Piotr Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18 
19 #define COBJMACROS
20 #define CONST_VTABLE
21 #ifndef __REACTOS__
22 #define NONAMELESSUNION
23 #endif
24 
25 #include <stdio.h>
26 #include <wine/test.h>
27 
28 #include "winbase.h"
29 #include "shlobj.h"
30 #include "shellapi.h"
31 #include "initguid.h"
32 
33 DEFINE_GUID(FMTID_Test,0x12345678,0x1234,0x1234,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12);
34 DEFINE_GUID(FMTID_NotExisting, 0x12345678,0x1234,0x1234,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x13);
35 DEFINE_GUID(CLSID_ClassMoniker, 0x0000031a,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
36 
37 #define DEFINE_EXPECT(func) \
38     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
39 
40 #define SET_EXPECT(func) \
41     expect_ ## func = TRUE
42 
43 #define CHECK_EXPECT2(func) \
44     do { \
45         ok(expect_ ##func, "unexpected call " #func "\n"); \
46         called_ ## func = TRUE; \
47     }while(0)
48 
49 #define CHECK_EXPECT(func) \
50     do { \
51         CHECK_EXPECT2(func); \
52         expect_ ## func = FALSE; \
53     }while(0)
54 
55 #define CHECK_CALLED(func) \
56     do { \
57         ok(called_ ## func, "expected " #func "\n"); \
58         expect_ ## func = called_ ## func = FALSE; \
59     }while(0)
60 
61 DEFINE_EXPECT(Create);
62 DEFINE_EXPECT(Delete);
63 DEFINE_EXPECT(Open);
64 DEFINE_EXPECT(ReadMultiple);
65 DEFINE_EXPECT(ReadMultipleCodePage);
66 DEFINE_EXPECT(Release);
67 DEFINE_EXPECT(Stat);
68 DEFINE_EXPECT(WriteMultiple);
69 
70 DEFINE_EXPECT(autoplay_BindToObject);
71 DEFINE_EXPECT(autoplay_GetClassObject);
72 
73 static HRESULT (WINAPI *pSHPropStgCreate)(IPropertySetStorage*, REFFMTID, const CLSID*,
74         DWORD, DWORD, DWORD, IPropertyStorage**, UINT*);
75 static HRESULT (WINAPI *pSHPropStgReadMultiple)(IPropertyStorage*, UINT,
76         ULONG, const PROPSPEC*, PROPVARIANT*);
77 static HRESULT (WINAPI *pSHPropStgWriteMultiple)(IPropertyStorage*, UINT*,
78         ULONG, const PROPSPEC*, PROPVARIANT*, PROPID);
79 static HRESULT (WINAPI *pSHCreateQueryCancelAutoPlayMoniker)(IMoniker**);
80 static HRESULT (WINAPI *pSHCreateSessionKey)(REGSAM, HKEY*);
81 
82 static void init(void)
83 {
84     HMODULE hmod = GetModuleHandleA("shell32.dll");
85 
86     pSHPropStgCreate = (void*)GetProcAddress(hmod, "SHPropStgCreate");
87     pSHPropStgReadMultiple = (void*)GetProcAddress(hmod, "SHPropStgReadMultiple");
88     pSHPropStgWriteMultiple = (void*)GetProcAddress(hmod, "SHPropStgWriteMultiple");
89     pSHCreateQueryCancelAutoPlayMoniker = (void*)GetProcAddress(hmod, "SHCreateQueryCancelAutoPlayMoniker");
90     pSHCreateSessionKey = (void*)GetProcAddress(hmod, (char*)723);
91 }
92 
93 static HRESULT WINAPI PropertyStorage_QueryInterface(IPropertyStorage *This,
94         REFIID riid, void **ppvObject)
95 {
96     ok(0, "unexpected call\n");
97     return E_NOTIMPL;
98 }
99 
100 static ULONG WINAPI PropertyStorage_AddRef(IPropertyStorage *This)
101 {
102     ok(0, "unexpected call\n");
103     return 2;
104 }
105 
106 static ULONG WINAPI PropertyStorage_Release(IPropertyStorage *This)
107 {
108     CHECK_EXPECT(Release);
109     return 1;
110 }
111 
112 static HRESULT WINAPI PropertyStorage_ReadMultiple(IPropertyStorage *This, ULONG cpspec,
113         const PROPSPEC *rgpspec, PROPVARIANT *rgpropvar)
114 {
115     if(cpspec == 1) {
116         CHECK_EXPECT(ReadMultipleCodePage);
117 
118         ok(rgpspec != NULL, "rgpspec = NULL\n");
119         ok(rgpropvar != NULL, "rgpropvar = NULL\n");
120 
121         ok(rgpspec[0].ulKind == PRSPEC_PROPID, "rgpspec[0].ulKind = %d\n", rgpspec[0].ulKind);
122         ok(rgpspec[0].propid == PID_CODEPAGE, "rgpspec[0].propid = %d\n", rgpspec[0].propid);
123 
124         rgpropvar[0].vt = VT_I2;
125         rgpropvar[0].iVal = 1234;
126     } else {
127         CHECK_EXPECT(ReadMultiple);
128 
129         ok(cpspec == 10, "cpspec = %u\n", cpspec);
130         ok(rgpspec == (void*)0xdeadbeef, "rgpspec = %p\n", rgpspec);
131         ok(rgpropvar != NULL, "rgpropvar = NULL\n");
132 
133         ok(rgpropvar[0].vt==0 || broken(rgpropvar[0].vt==VT_BSTR), "rgpropvar[0].vt = %d\n", rgpropvar[0].vt);
134 
135         rgpropvar[0].vt = VT_BSTR;
136         rgpropvar[0].bstrVal = (void*)0xdeadbeef;
137         rgpropvar[1].vt = VT_LPSTR;
138         rgpropvar[1].pszVal = (void*)0xdeadbeef;
139         rgpropvar[2].vt = VT_BYREF|VT_I1;
140         rgpropvar[2].pcVal = (void*)0xdeadbeef;
141         rgpropvar[3].vt = VT_BYREF|VT_VARIANT;
142         rgpropvar[3].pvarVal = (void*)0xdeadbeef;
143     }
144 
145     return S_OK;
146 }
147 
148 static HRESULT WINAPI PropertyStorage_WriteMultiple(IPropertyStorage *This, ULONG cpspec,
149         const PROPSPEC *rgpspec, const PROPVARIANT *rgpropvar,
150         PROPID propidNameFirst)
151 {
152     CHECK_EXPECT(WriteMultiple);
153 
154     ok(cpspec == 20, "cpspec = %d\n", cpspec);
155     ok(rgpspec == (void*)0xdeadbeef, "rgpspec = %p\n", rgpspec);
156     ok(rgpropvar == (void*)0xdeadbeef, "rgpropvar = %p\n", rgpspec);
157     ok(propidNameFirst == PID_FIRST_USABLE, "propidNameFirst = %d\n", propidNameFirst);
158     return S_OK;
159 }
160 
161 static HRESULT WINAPI PropertyStorage_DeleteMultiple(IPropertyStorage *This, ULONG cpspec,
162         const PROPSPEC *rgpspec)
163 {
164     ok(0, "unexpected call\n");
165     return E_NOTIMPL;
166 }
167 
168 static HRESULT WINAPI PropertyStorage_ReadPropertyNames(IPropertyStorage *This, ULONG cpropid,
169         const PROPID *rgpropid, LPOLESTR *rglpwstrName)
170 {
171     ok(0, "unexpected call\n");
172     return E_NOTIMPL;
173 }
174 
175 static HRESULT WINAPI PropertyStorage_WritePropertyNames(IPropertyStorage *This, ULONG cpropid,
176         const PROPID *rgpropid, const LPOLESTR *rglpwstrName)
177 {
178     ok(0, "unexpected call\n");
179     return E_NOTIMPL;
180 }
181 
182 static HRESULT WINAPI PropertyStorage_DeletePropertyNames(IPropertyStorage *This, ULONG cpropid,
183         const PROPID *rgpropid)
184 {
185     ok(0, "unexpected call\n");
186     return E_NOTIMPL;
187 }
188 
189 static HRESULT WINAPI PropertyStorage_Commit(IPropertyStorage *This, DWORD grfCommitFlags)
190 {
191     ok(0, "unexpected call\n");
192     return E_NOTIMPL;
193 }
194 
195 static HRESULT WINAPI PropertyStorage_Revert(IPropertyStorage *This)
196 {
197     ok(0, "unexpected call\n");
198     return E_NOTIMPL;
199 }
200 
201 static HRESULT WINAPI PropertyStorage_Enum(IPropertyStorage *This, IEnumSTATPROPSTG **ppenum)
202 {
203     ok(0, "unexpected call\n");
204     return E_NOTIMPL;
205 }
206 
207 static HRESULT WINAPI PropertyStorage_SetTimes(IPropertyStorage *This, const FILETIME *pctime,
208         const FILETIME *patime, const FILETIME *pmtime)
209 {
210     ok(0, "unexpected call\n");
211     return E_NOTIMPL;
212 }
213 
214 static HRESULT WINAPI PropertyStorage_SetClass(IPropertyStorage *This, REFCLSID clsid)
215 {
216     ok(0, "unexpected call\n");
217     return E_NOTIMPL;
218 }
219 
220 static HRESULT WINAPI PropertyStorage_Stat(IPropertyStorage *This, STATPROPSETSTG *statpsstg)
221 {
222     CHECK_EXPECT(Stat);
223 
224     memset(statpsstg, 0, sizeof(STATPROPSETSTG));
225     memcpy(&statpsstg->fmtid, &FMTID_Test, sizeof(FMTID));
226     statpsstg->grfFlags = PROPSETFLAG_ANSI;
227     return S_OK;
228 }
229 
230 static IPropertyStorageVtbl PropertyStorageVtbl = {
231     PropertyStorage_QueryInterface,
232     PropertyStorage_AddRef,
233     PropertyStorage_Release,
234     PropertyStorage_ReadMultiple,
235     PropertyStorage_WriteMultiple,
236     PropertyStorage_DeleteMultiple,
237     PropertyStorage_ReadPropertyNames,
238     PropertyStorage_WritePropertyNames,
239     PropertyStorage_DeletePropertyNames,
240     PropertyStorage_Commit,
241     PropertyStorage_Revert,
242     PropertyStorage_Enum,
243     PropertyStorage_SetTimes,
244     PropertyStorage_SetClass,
245     PropertyStorage_Stat
246 };
247 
248 static IPropertyStorage PropertyStorage = { &PropertyStorageVtbl };
249 
250 static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *This,
251         REFIID riid, void **ppvObject)
252 {
253     ok(0, "unexpected call\n");
254     return E_NOTIMPL;
255 }
256 
257 static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *This)
258 {
259     ok(0, "unexpected call\n");
260     return 2;
261 }
262 
263 static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *This)
264 {
265     ok(0, "unexpected call\n");
266     return 1;
267 }
268 
269 static HRESULT WINAPI PropertySetStorage_Create(IPropertySetStorage *This,
270         REFFMTID rfmtid, const CLSID *pclsid, DWORD grfFlags,
271         DWORD grfMode, IPropertyStorage **ppprstg)
272 {
273     CHECK_EXPECT(Create);
274     ok(IsEqualGUID(rfmtid, &FMTID_Test) || IsEqualGUID(rfmtid, &FMTID_NotExisting),
275             "Incorrect rfmtid value\n");
276     ok(pclsid == NULL, "pclsid != NULL\n");
277     ok(grfFlags == PROPSETFLAG_ANSI, "grfFlags = %x\n", grfFlags);
278     ok(grfMode == STGM_READ, "grfMode = %x\n", grfMode);
279 
280     *ppprstg = &PropertyStorage;
281     return S_OK;
282 }
283 
284 static HRESULT WINAPI PropertySetStorage_Open(IPropertySetStorage *This,
285         REFFMTID rfmtid, DWORD grfMode, IPropertyStorage **ppprstg)
286 {
287     CHECK_EXPECT(Open);
288 
289     if(IsEqualGUID(rfmtid, &FMTID_Test)) {
290         ok(grfMode == STGM_READ, "grfMode = %x\n", grfMode);
291 
292         *ppprstg = &PropertyStorage;
293         return S_OK;
294     }
295 
296     return STG_E_FILENOTFOUND;
297 }
298 
299 static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *This,
300         REFFMTID rfmtid)
301 {
302     CHECK_EXPECT(Delete);
303     ok(IsEqualGUID(rfmtid, &FMTID_Test), "wrong rfmtid value\n");
304     return S_OK;
305 }
306 
307 static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *This,
308         IEnumSTATPROPSETSTG **ppenum)
309 {
310     ok(0, "unexpected call\n");
311     return E_NOTIMPL;
312 }
313 
314 static IPropertySetStorageVtbl PropertySetStorageVtbl = {
315     PropertySetStorage_QueryInterface,
316     PropertySetStorage_AddRef,
317     PropertySetStorage_Release,
318     PropertySetStorage_Create,
319     PropertySetStorage_Open,
320     PropertySetStorage_Delete,
321     PropertySetStorage_Enum
322 };
323 
324 static IPropertySetStorage PropertySetStorage = { &PropertySetStorageVtbl };
325 
326 static void test_SHPropStg_functions(void)
327 {
328     IPropertyStorage *property_storage;
329     UINT codepage;
330     PROPVARIANT read[10];
331     HRESULT hres;
332 
333     if(!pSHPropStgCreate || !pSHPropStgReadMultiple || !pSHPropStgWriteMultiple) {
334         win_skip("SHPropStg* functions are missing\n");
335         return;
336     }
337 
338     if(0) {
339         /* Crashes on Windows */
340         pSHPropStgCreate(NULL, &FMTID_Test, NULL, PROPSETFLAG_DEFAULT,
341                 STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
342         pSHPropStgCreate(&PropertySetStorage, NULL, NULL, PROPSETFLAG_DEFAULT,
343                 STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
344         pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, NULL, PROPSETFLAG_DEFAULT,
345                 STGM_READ, OPEN_EXISTING, NULL, &codepage);
346     }
347 
348     SET_EXPECT(Open);
349     SET_EXPECT(ReadMultipleCodePage);
350     hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, NULL, PROPSETFLAG_DEFAULT,
351             STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
352     ok(codepage == 1234, "codepage = %d\n", codepage);
353     ok(hres == S_OK, "hres = %x\n", hres);
354     CHECK_CALLED(Open);
355     CHECK_CALLED(ReadMultipleCodePage);
356 
357     SET_EXPECT(Open);
358     hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_NotExisting, NULL,
359             PROPSETFLAG_DEFAULT, STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
360     ok(hres == STG_E_FILENOTFOUND, "hres = %x\n", hres);
361     CHECK_CALLED(Open);
362 
363     SET_EXPECT(Open);
364     SET_EXPECT(Release);
365     SET_EXPECT(Delete);
366     SET_EXPECT(Create);
367     SET_EXPECT(ReadMultipleCodePage);
368     hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, NULL, PROPSETFLAG_ANSI,
369             STGM_READ, CREATE_ALWAYS, &property_storage, &codepage);
370     ok(codepage == 1234, "codepage = %d\n", codepage);
371     ok(hres == S_OK, "hres = %x\n", hres);
372     CHECK_CALLED(Open);
373     CHECK_CALLED(Release);
374     CHECK_CALLED(Delete);
375     CHECK_CALLED(Create);
376     CHECK_CALLED(ReadMultipleCodePage);
377 
378     SET_EXPECT(Open);
379     SET_EXPECT(Create);
380     SET_EXPECT(ReadMultipleCodePage);
381     hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_NotExisting, NULL, PROPSETFLAG_ANSI,
382             STGM_READ, CREATE_ALWAYS, &property_storage, &codepage);
383     ok(codepage == 1234, "codepage = %d\n", codepage);
384     ok(hres == S_OK, "hres = %x\n", hres);
385     CHECK_CALLED(Open);
386     CHECK_CALLED(Create);
387     CHECK_CALLED(ReadMultipleCodePage);
388 
389     SET_EXPECT(Open);
390     hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, &FMTID_NotExisting,
391             PROPSETFLAG_DEFAULT, STGM_READ, OPEN_EXISTING, &property_storage, NULL);
392     ok(hres == S_OK, "hres = %x\n", hres);
393     CHECK_CALLED(Open);
394 
395     SET_EXPECT(Stat);
396     SET_EXPECT(ReadMultipleCodePage);
397     SET_EXPECT(WriteMultiple);
398     codepage = 0;
399     hres = pSHPropStgWriteMultiple(property_storage, &codepage, 20, (void*)0xdeadbeef, (void*)0xdeadbeef, PID_FIRST_USABLE);
400     ok(hres == S_OK, "hres = %x\n", hres);
401     ok(codepage == 1234, "codepage = %d\n", codepage);
402     CHECK_CALLED(Stat);
403     CHECK_CALLED(ReadMultipleCodePage);
404     CHECK_CALLED(WriteMultiple);
405 
406     SET_EXPECT(Stat);
407     SET_EXPECT(ReadMultipleCodePage);
408     SET_EXPECT(WriteMultiple);
409     hres = pSHPropStgWriteMultiple(property_storage, NULL, 20, (void*)0xdeadbeef, (void*)0xdeadbeef, PID_FIRST_USABLE);
410     ok(hres == S_OK, "hres = %x\n", hres);
411     CHECK_CALLED(Stat);
412     CHECK_CALLED(ReadMultipleCodePage);
413     CHECK_CALLED(WriteMultiple);
414 
415     SET_EXPECT(Stat);
416     SET_EXPECT(WriteMultiple);
417     codepage = 1000;
418     hres = pSHPropStgWriteMultiple(property_storage, &codepage, 20, (void*)0xdeadbeef, (void*)0xdeadbeef, PID_FIRST_USABLE);
419     ok(hres == S_OK, "hres = %x\n", hres);
420     ok(codepage == 1000, "codepage = %d\n", codepage);
421     CHECK_CALLED(Stat);
422     CHECK_CALLED(WriteMultiple);
423 
424     read[0].vt = VT_BSTR;
425     read[0].bstrVal = (void*)0xdeadbeef;
426     SET_EXPECT(ReadMultiple);
427     SET_EXPECT(ReadMultipleCodePage);
428     SET_EXPECT(Stat);
429     hres = pSHPropStgReadMultiple(property_storage, 0, 10, (void*)0xdeadbeef, read);
430     ok(hres == S_OK, "hres = %x\n", hres);
431     CHECK_CALLED(ReadMultiple);
432     CHECK_CALLED(ReadMultipleCodePage);
433     CHECK_CALLED(Stat);
434 
435     SET_EXPECT(ReadMultiple);
436     SET_EXPECT(Stat);
437     hres = pSHPropStgReadMultiple(property_storage, 1251, 10, (void*)0xdeadbeef, read);
438     ok(hres == S_OK, "hres = %x\n", hres);
439     CHECK_CALLED(ReadMultiple);
440     CHECK_CALLED(Stat);
441 }
442 
443 static HRESULT WINAPI test_activator_QI(IClassActivator *iface, REFIID riid, void **ppv)
444 {
445     *ppv = NULL;
446 
447     if (IsEqualIID(riid, &IID_IUnknown) ||
448         IsEqualIID(riid, &IID_IClassActivator))
449     {
450         *ppv = iface;
451     }
452 
453     if (!*ppv) return E_NOINTERFACE;
454 
455     IClassActivator_AddRef(iface);
456 
457     return S_OK;
458 }
459 
460 static ULONG WINAPI test_activator_AddRef(IClassActivator *iface)
461 {
462     return 2;
463 }
464 
465 static ULONG WINAPI test_activator_Release(IClassActivator *iface)
466 {
467     return 1;
468 }
469 
470 static HRESULT WINAPI test_activator_GetClassObject(IClassActivator *iface, REFCLSID clsid,
471     DWORD context, LCID locale, REFIID riid, void **ppv)
472 {
473     CHECK_EXPECT(autoplay_GetClassObject);
474     ok(IsEqualGUID(clsid, &CLSID_QueryCancelAutoPlay), "clsid %s\n", wine_dbgstr_guid(clsid));
475     ok(IsEqualIID(riid, &IID_IQueryCancelAutoPlay), "riid %s\n", wine_dbgstr_guid(riid));
476     return E_NOTIMPL;
477 }
478 
479 static const IClassActivatorVtbl test_activator_vtbl = {
480     test_activator_QI,
481     test_activator_AddRef,
482     test_activator_Release,
483     test_activator_GetClassObject
484 };
485 
486 static IClassActivator test_activator = { &test_activator_vtbl };
487 
488 static HRESULT WINAPI test_moniker_QueryInterface(IMoniker* iface, REFIID riid, void **ppvObject)
489 {
490     *ppvObject = 0;
491 
492     if (IsEqualIID(&IID_IUnknown, riid) ||
493         IsEqualIID(&IID_IPersist, riid) ||
494         IsEqualIID(&IID_IPersistStream, riid) ||
495         IsEqualIID(&IID_IMoniker, riid))
496     {
497         *ppvObject = iface;
498     }
499 
500     if (!*ppvObject)
501         return E_NOINTERFACE;
502 
503     return S_OK;
504 }
505 
506 static ULONG WINAPI test_moniker_AddRef(IMoniker* iface)
507 {
508     return 2;
509 }
510 
511 static ULONG WINAPI test_moniker_Release(IMoniker* iface)
512 {
513     return 1;
514 }
515 
516 static HRESULT WINAPI test_moniker_GetClassID(IMoniker* iface, CLSID *pClassID)
517 {
518     ok(0, "unexpected call\n");
519     return E_NOTIMPL;
520 }
521 
522 static HRESULT WINAPI test_moniker_IsDirty(IMoniker* iface)
523 {
524     ok(0, "unexpected call\n");
525     return E_NOTIMPL;
526 }
527 
528 static HRESULT WINAPI test_moniker_Load(IMoniker* iface, IStream* pStm)
529 {
530     ok(0, "unexpected call\n");
531     return E_NOTIMPL;
532 }
533 
534 static HRESULT WINAPI test_moniker_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
535 {
536     ok(0, "unexpected call\n");
537     return E_NOTIMPL;
538 }
539 
540 static HRESULT WINAPI test_moniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
541 {
542     ok(0, "unexpected call\n");
543     return E_NOTIMPL;
544 }
545 
546 static HRESULT WINAPI test_moniker_BindToObject(IMoniker* iface,
547                                                 IBindCtx* pbc,
548                                                 IMoniker* moniker_to_left,
549                                                 REFIID riid,
550                                                 void** ppv)
551 {
552     CHECK_EXPECT(autoplay_BindToObject);
553     ok(pbc != NULL, "got %p\n", pbc);
554     ok(moniker_to_left == NULL, "got %p\n", moniker_to_left);
555     ok(IsEqualIID(riid, &IID_IClassActivator), "got riid %s\n", wine_dbgstr_guid(riid));
556 
557     if (IsEqualIID(riid, &IID_IClassActivator))
558     {
559         *ppv = &test_activator;
560         return S_OK;
561     }
562 
563     return E_NOTIMPL;
564 }
565 
566 static HRESULT WINAPI test_moniker_BindToStorage(IMoniker* iface,
567                                              IBindCtx* pbc,
568                                              IMoniker* pmkToLeft,
569                                              REFIID riid,
570                                              VOID** ppvResult)
571 {
572     ok(0, "unexpected call\n");
573     return E_NOTIMPL;
574 }
575 
576 static HRESULT WINAPI test_moniker_Reduce(IMoniker* iface,
577                                       IBindCtx* pbc,
578                                       DWORD dwReduceHowFar,
579                                       IMoniker** ppmkToLeft,
580                                       IMoniker** ppmkReduced)
581 {
582     ok(0, "unexpected call\n");
583     return E_NOTIMPL;
584 }
585 
586 static HRESULT WINAPI test_moniker_ComposeWith(IMoniker* iface,
587                                            IMoniker* pmkRight,
588                                            BOOL fOnlyIfNotGeneric,
589                                            IMoniker** ppmkComposite)
590 {
591     ok(0, "unexpected call\n");
592     return E_NOTIMPL;
593 }
594 
595 static HRESULT WINAPI test_moniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
596 {
597     ok(0, "unexpected call\n");
598     return E_NOTIMPL;
599 }
600 
601 static HRESULT WINAPI test_moniker_IsEqual(IMoniker* iface, IMoniker* pmkOtherMoniker)
602 {
603     ok(0, "unexpected call\n");
604     return E_NOTIMPL;
605 }
606 
607 static HRESULT WINAPI test_moniker_Hash(IMoniker* iface, DWORD* pdwHash)
608 {
609     ok(0, "unexpected call\n");
610     return E_NOTIMPL;
611 }
612 
613 static HRESULT WINAPI test_moniker_IsRunning(IMoniker* iface,
614                                          IBindCtx* pbc,
615                                          IMoniker* pmkToLeft,
616                                          IMoniker* pmkNewlyRunning)
617 {
618     ok(0, "unexpected call\n");
619     return E_NOTIMPL;
620 }
621 
622 static HRESULT WINAPI test_moniker_GetTimeOfLastChange(IMoniker* iface,
623                                                    IBindCtx* pbc,
624                                                    IMoniker* pmkToLeft,
625                                                    FILETIME* pItemTime)
626 {
627     ok(0, "unexpected call\n");
628     return E_NOTIMPL;
629 }
630 
631 static HRESULT WINAPI test_moniker_Inverse(IMoniker* iface, IMoniker** ppmk)
632 {
633     ok(0, "unexpected call\n");
634     return E_NOTIMPL;
635 }
636 
637 static HRESULT WINAPI test_moniker_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
638 {
639     ok(0, "unexpected call\n");
640     return E_NOTIMPL;
641 }
642 
643 static HRESULT WINAPI test_moniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
644 {
645     ok(0, "unexpected call\n");
646     return E_NOTIMPL;
647 }
648 
649 static HRESULT WINAPI test_moniker_GetDisplayName(IMoniker* iface,
650                                               IBindCtx* pbc,
651                                               IMoniker* pmkToLeft,
652                                               LPOLESTR *ppszDisplayName)
653 {
654     ok(0, "unexpected call\n");
655     return E_NOTIMPL;
656 }
657 
658 static HRESULT WINAPI test_moniker_ParseDisplayName(IMoniker* iface,
659                                                 IBindCtx* pbc,
660                                                 IMoniker* pmkToLeft,
661                                                 LPOLESTR pszDisplayName,
662                                                 ULONG* pchEaten,
663                                                 IMoniker** ppmkOut)
664 {
665     ok(0, "unexpected call\n");
666     return E_NOTIMPL;
667 }
668 
669 static HRESULT WINAPI test_moniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
670 {
671     ok(0, "unexpected call\n");
672     return E_NOTIMPL;
673 }
674 
675 static const IMonikerVtbl test_moniker_vtbl =
676 {
677     test_moniker_QueryInterface,
678     test_moniker_AddRef,
679     test_moniker_Release,
680     test_moniker_GetClassID,
681     test_moniker_IsDirty,
682     test_moniker_Load,
683     test_moniker_Save,
684     test_moniker_GetSizeMax,
685     test_moniker_BindToObject,
686     test_moniker_BindToStorage,
687     test_moniker_Reduce,
688     test_moniker_ComposeWith,
689     test_moniker_Enum,
690     test_moniker_IsEqual,
691     test_moniker_Hash,
692     test_moniker_IsRunning,
693     test_moniker_GetTimeOfLastChange,
694     test_moniker_Inverse,
695     test_moniker_CommonPrefixWith,
696     test_moniker_RelativePathTo,
697     test_moniker_GetDisplayName,
698     test_moniker_ParseDisplayName,
699     test_moniker_IsSystemMoniker
700 };
701 
702 static IMoniker test_moniker = { &test_moniker_vtbl };
703 
704 static void test_SHCreateQueryCancelAutoPlayMoniker(void)
705 {
706     IBindCtx *ctxt;
707     IMoniker *mon;
708     IUnknown *unk;
709     CLSID clsid;
710     HRESULT hr;
711     DWORD sys;
712 
713     if (!pSHCreateQueryCancelAutoPlayMoniker)
714     {
715         win_skip("SHCreateQueryCancelAutoPlayMoniker is not available, skipping tests.\n");
716         return;
717     }
718 
719     hr = pSHCreateQueryCancelAutoPlayMoniker(NULL);
720     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
721 
722     hr = pSHCreateQueryCancelAutoPlayMoniker(&mon);
723     ok(hr == S_OK, "got 0x%08x\n", hr);
724 
725     sys = -1;
726     hr = IMoniker_IsSystemMoniker(mon, &sys);
727     ok(hr == S_OK, "got 0x%08x\n", hr);
728     ok(sys == MKSYS_CLASSMONIKER, "got %d\n", sys);
729 
730     memset(&clsid, 0, sizeof(clsid));
731     hr = IMoniker_GetClassID(mon, &clsid);
732     ok(hr == S_OK, "got 0x%08x\n", hr);
733     ok(IsEqualGUID(&clsid, &CLSID_ClassMoniker), "got %s\n", wine_dbgstr_guid(&clsid));
734 
735     /* extract used CLSID that implements this hook */
736     SET_EXPECT(autoplay_BindToObject);
737     SET_EXPECT(autoplay_GetClassObject);
738 
739     CreateBindCtx(0, &ctxt);
740     hr = IMoniker_BindToObject(mon, ctxt, &test_moniker, &IID_IQueryCancelAutoPlay, (void**)&unk);
741     ok(hr == E_NOTIMPL, "got 0x%08x\n", hr);
742     IBindCtx_Release(ctxt);
743 
744     CHECK_CALLED(autoplay_BindToObject);
745     CHECK_CALLED(autoplay_GetClassObject);
746 
747     IMoniker_Release(mon);
748 }
749 
750 #define WM_EXPECTED_VALUE WM_APP
751 #define DROPTEST_FILENAME "c:\\wintest.bin"
752 struct DragParam {
753     HWND hwnd;
754     HANDLE ready;
755 };
756 
757 static LRESULT WINAPI drop_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
758 {
759     static BOOL expected;
760 
761     switch (msg) {
762     case WM_EXPECTED_VALUE:
763     {
764         expected = lparam;
765         break;
766     }
767     case WM_DROPFILES:
768     {
769         HDROP hDrop = (HDROP)wparam;
770         char filename[MAX_PATH] = "dummy";
771         POINT pt;
772         BOOL r;
773         UINT num;
774         num = DragQueryFileA(hDrop, 0xffffffff, NULL, 0);
775         ok(num == 1, "expected 1, got %u\n", num);
776         num = DragQueryFileA(hDrop, 0xffffffff, (char*)0xdeadbeef, 0xffffffff);
777         ok(num == 1, "expected 1, got %u\n", num);
778         num = DragQueryFileA(hDrop, 0, filename, sizeof(filename));
779         ok(num == strlen(DROPTEST_FILENAME), "got %u\n", num);
780         ok(!strcmp(filename, DROPTEST_FILENAME), "got %s\n", filename);
781         r = DragQueryPoint(hDrop, &pt);
782         ok(r == expected, "expected %d, got %d\n", expected, r);
783         ok(pt.x == 10, "expected 10, got %d\n", pt.x);
784         ok(pt.y == 20, "expected 20, got %d\n", pt.y);
785         DragFinish(hDrop);
786         return 0;
787     }
788     }
789     return DefWindowProcA(hwnd, msg, wparam, lparam);
790 }
791 
792 static DWORD WINAPI drop_window_therad(void *arg)
793 {
794     struct DragParam *param = arg;
795     WNDCLASSA cls;
796     WINDOWINFO info;
797     BOOL r;
798     MSG msg;
799 
800     memset(&cls, 0, sizeof(cls));
801     cls.lpfnWndProc = drop_window_proc;
802     cls.hInstance = GetModuleHandleA(NULL);
803     cls.lpszClassName = "drop test";
804     RegisterClassA(&cls);
805 
806     param->hwnd = CreateWindowA("drop test", NULL, 0, 0, 0, 0, 0,
807                                 NULL, 0, NULL, 0);
808     ok(param->hwnd != NULL, "CreateWindow failed: %d\n", GetLastError());
809 
810     memset(&info, 0, sizeof(info));
811     info.cbSize = sizeof(info);
812     r = GetWindowInfo(param->hwnd, &info);
813     ok(r, "got %d\n", r);
814     ok(!(info.dwExStyle & WS_EX_ACCEPTFILES), "got %08x\n", info.dwExStyle);
815 
816     DragAcceptFiles(param->hwnd, TRUE);
817 
818     memset(&info, 0, sizeof(info));
819     info.cbSize = sizeof(info);
820     r = GetWindowInfo(param->hwnd, &info);
821     ok(r, "got %d\n", r);
822     ok((info.dwExStyle & WS_EX_ACCEPTFILES), "got %08x\n", info.dwExStyle);
823 
824     SetEvent(param->ready);
825 
826     while ((r = GetMessageA(&msg, NULL, 0, 0)) != 0) {
827         if (r == (BOOL)-1) {
828             ok(0, "unexpected return value, got %d\n", r);
829             break;
830         }
831         DispatchMessageA(&msg);
832     }
833 
834     DestroyWindow(param->hwnd);
835     UnregisterClassA("drop test", GetModuleHandleA(NULL));
836     return 0;
837 }
838 
839 static void test_DragQueryFile(BOOL non_client_flag)
840 {
841     struct DragParam param;
842     HANDLE hThread;
843     DWORD rc;
844     HGLOBAL hDrop;
845     DROPFILES *pDrop;
846     int ret;
847     BOOL r;
848 
849     param.ready = CreateEventA(NULL, FALSE, FALSE, NULL);
850     ok(param.ready != NULL, "can't create event\n");
851     hThread = CreateThread(NULL, 0, drop_window_therad, &param, 0, NULL);
852 
853     rc = WaitForSingleObject(param.ready, 5000);
854     ok(rc == WAIT_OBJECT_0, "got %u\n", rc);
855 
856     hDrop = GlobalAlloc(GHND, sizeof(DROPFILES) + (strlen(DROPTEST_FILENAME) + 2) * sizeof(WCHAR));
857     pDrop = GlobalLock(hDrop);
858     pDrop->pt.x = 10;
859     pDrop->pt.y = 20;
860     pDrop->fNC = non_client_flag;
861     pDrop->pFiles = sizeof(DROPFILES);
862     ret = MultiByteToWideChar(CP_ACP, 0, DROPTEST_FILENAME, -1,
863                               (LPWSTR)(pDrop + 1), strlen(DROPTEST_FILENAME) + 1);
864     ok(ret > 0, "got %d\n", ret);
865     pDrop->fWide = TRUE;
866     GlobalUnlock(hDrop);
867 
868     r = PostMessageA(param.hwnd, WM_EXPECTED_VALUE, 0, !non_client_flag);
869     ok(r, "got %d\n", r);
870 
871     r = PostMessageA(param.hwnd, WM_DROPFILES, (WPARAM)hDrop, 0);
872     ok(r, "got %d\n", r);
873 
874     r = PostMessageA(param.hwnd, WM_QUIT, 0, 0);
875     ok(r, "got %d\n", r);
876 
877     rc = WaitForSingleObject(hThread, 5000);
878     ok(rc == WAIT_OBJECT_0, "got %d\n", rc);
879 
880     CloseHandle(param.ready);
881     CloseHandle(hThread);
882 }
883 #undef WM_EXPECTED_VALUE
884 #undef DROPTEST_FILENAME
885 
886 static void test_SHCreateSessionKey(void)
887 {
888     static const WCHAR session_format[] = {
889                 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
890                 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
891                 'E','x','p','l','o','r','e','r','\\','S','e','s','s','i','o','n','I','n','f','o','\\','%','u',0};
892     HKEY hkey, hkey2;
893     HRESULT hr;
894     DWORD session;
895     WCHAR sessionW[ARRAY_SIZE(session_format) + 16];
896     LONG ret;
897 
898     if (!pSHCreateSessionKey)
899     {
900         win_skip("SHCreateSessionKey is not implemented\n");
901         return;
902     }
903 
904     if (0) /* crashes on native */
905         hr = pSHCreateSessionKey(KEY_READ, NULL);
906 
907     hkey = (HKEY)0xdeadbeef;
908     hr = pSHCreateSessionKey(0, &hkey);
909     ok(hr == E_ACCESSDENIED, "got 0x%08x\n", hr);
910     ok(hkey == NULL, "got %p\n", hkey);
911 
912     hr = pSHCreateSessionKey(KEY_READ, &hkey);
913     ok(hr == S_OK, "got 0x%08x\n", hr);
914 
915     hr = pSHCreateSessionKey(KEY_READ, &hkey2);
916     ok(hr == S_OK, "got 0x%08x\n", hr);
917     ok(hkey != hkey2, "got %p, %p\n", hkey, hkey2);
918 
919     RegCloseKey(hkey);
920     RegCloseKey(hkey2);
921 
922     /* check the registry */
923     ProcessIdToSessionId( GetCurrentProcessId(), &session);
924     if (session)
925     {
926         wsprintfW(sessionW, session_format, session);
927         ret = RegOpenKeyW(HKEY_CURRENT_USER, sessionW, &hkey);
928         ok(!ret, "key not found\n");
929         RegCloseKey(hkey);
930     }
931 }
932 
933 static void test_dragdrophelper(void)
934 {
935     IDragSourceHelper *dragsource;
936     IDropTargetHelper *target;
937     HRESULT hr;
938 
939     hr = CoCreateInstance(&CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, &IID_IDropTargetHelper, (void **)&target);
940     ok(hr == S_OK, "Failed to create IDropTargetHelper, %#x\n", hr);
941 
942     hr = IDropTargetHelper_QueryInterface(target, &IID_IDragSourceHelper, (void **)&dragsource);
943     ok(hr == S_OK, "QI failed, %#x\n", hr);
944     IDragSourceHelper_Release(dragsource);
945 
946     IDropTargetHelper_Release(target);
947 }
948 
949 START_TEST(shellole)
950 {
951     HRESULT hr;
952 
953     init();
954 
955     hr = CoInitialize(NULL);
956     ok(hr == S_OK, "CoInitialize failed (0x%08x)\n", hr);
957     if (hr != S_OK)
958         return;
959 
960     test_SHPropStg_functions();
961     test_SHCreateQueryCancelAutoPlayMoniker();
962     test_DragQueryFile(TRUE);
963     test_DragQueryFile(FALSE);
964     test_SHCreateSessionKey();
965     test_dragdrophelper();
966 
967     CoUninitialize();
968 }
969