oleaut32/tests: Use IsEqualIID instead of memcmp to compare REFIIDs.
[wine] / dlls / ole32 / pointermoniker.c
1 /*
2  * Pointer Moniker Implementation
3  *
4  * Copyright 1999 Noomen Hamza
5  * Copyright 2008 Robert Shearman (for CodeWeavers)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24
25 #define COBJMACROS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
32 #include "winuser.h"
33 #include "objbase.h"
34 #include "oleidl.h"
35 #include "wine/debug.h"
36 #include "moniker.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39
40 /* PointerMoniker data structure */
41 typedef struct PointerMonikerImpl{
42
43     const IMonikerVtbl*  lpvtbl;  /* VTable relative to the IMoniker interface.*/
44
45     LONG ref; /* reference counter for this object */
46
47     IUnknown *pObject; /* custom marshaler */
48 } PointerMonikerImpl;
49
50 static HRESULT WINAPI
51 PointerMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
52 {
53     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
54
55     TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
56
57     /* Perform a sanity check on the parameters.*/
58     if ( (This==0) || (ppvObject==0) )
59         return E_INVALIDARG;
60
61     /* Initialize the return parameter */
62     *ppvObject = 0;
63
64     /* Compare the riid with the interface IDs implemented by this object.*/
65     if (IsEqualIID(&IID_IUnknown, riid) ||
66         IsEqualIID(&IID_IPersist, riid) ||
67         IsEqualIID(&IID_IPersistStream, riid) ||
68         IsEqualIID(&IID_IMoniker, riid))
69         *ppvObject = iface;
70
71     /* Check that we obtained an interface.*/
72     if ((*ppvObject)==0)
73         return E_NOINTERFACE;
74
75     /* always increase the reference count by one when it is successful */
76     IMoniker_AddRef(iface);
77
78     return S_OK;
79 }
80
81 /******************************************************************************
82  *        PointerMoniker_AddRef
83  ******************************************************************************/
84 static ULONG WINAPI
85 PointerMonikerImpl_AddRef(IMoniker* iface)
86 {
87     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
88
89     TRACE("(%p)\n",This);
90
91     return InterlockedIncrement(&This->ref);
92 }
93
94 /******************************************************************************
95  *        PointerMoniker_Release
96  ******************************************************************************/
97 static ULONG WINAPI
98 PointerMonikerImpl_Release(IMoniker* iface)
99 {
100     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
101     ULONG ref;
102
103     TRACE("(%p)\n",This);
104
105     ref = InterlockedDecrement(&This->ref);
106
107     /* destroy the object if there's no more reference on it */
108     if (ref == 0)
109     {
110         if (This->pObject) IUnknown_Release(This->pObject);
111         HeapFree(GetProcessHeap(),0,This);
112     }
113
114     return ref;
115 }
116
117 /******************************************************************************
118  *        PointerMoniker_GetClassID
119  ******************************************************************************/
120 static HRESULT WINAPI
121 PointerMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
122 {
123     TRACE("(%p,%p)\n",iface,pClassID);
124
125     if (pClassID==NULL)
126         return E_POINTER;
127
128     *pClassID = CLSID_PointerMoniker;
129
130     return S_OK;
131 }
132
133 /******************************************************************************
134  *        PointerMoniker_IsDirty
135  ******************************************************************************/
136 static HRESULT WINAPI
137 PointerMonikerImpl_IsDirty(IMoniker* iface)
138 {
139     /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
140        method in the OLE-provided moniker interfaces always return S_FALSE because
141        their internal state never changes. */
142
143     TRACE("(%p)\n",iface);
144
145     return S_FALSE;
146 }
147
148 /******************************************************************************
149  *        PointerMoniker_Load
150  ******************************************************************************/
151 static HRESULT WINAPI
152 PointerMonikerImpl_Load(IMoniker* iface,IStream* pStm)
153 {
154     TRACE("(%p)\n", pStm);
155
156     return E_NOTIMPL;
157 }
158
159 /******************************************************************************
160  *        PointerMoniker_Save
161  ******************************************************************************/
162 static HRESULT WINAPI
163 PointerMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
164 {
165     TRACE("(%p, %d)\n", pStm, fClearDirty);
166
167     return E_NOTIMPL;
168 }
169
170 /******************************************************************************
171  *        PointerMoniker_GetSizeMax
172  *
173  * PARAMS
174  * pcbSize [out] Pointer to size of stream needed to save object
175  ******************************************************************************/
176 static HRESULT WINAPI
177 PointerMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
178 {
179     TRACE("(%p,%p)\n",iface,pcbSize);
180
181     if (!pcbSize)
182         return E_POINTER;
183
184     pcbSize->u.LowPart = 0;
185     pcbSize->u.HighPart = 0;
186
187     return E_NOTIMPL;
188 }
189
190 /******************************************************************************
191  *                  PointerMoniker_BindToObject
192  ******************************************************************************/
193 static HRESULT WINAPI
194 PointerMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
195                              REFIID riid, VOID** ppvResult)
196 {
197     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
198
199     TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
200
201     if (!This->pObject)
202         return E_UNEXPECTED;
203
204     return IUnknown_QueryInterface(This->pObject, riid, ppvResult);
205 }
206
207 /******************************************************************************
208  *        PointerMoniker_BindToStorage
209  ******************************************************************************/
210 static HRESULT WINAPI
211 PointerMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
212                               REFIID riid, VOID** ppvResult)
213 {
214     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
215
216     TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
217
218     if (!This->pObject)
219         return E_UNEXPECTED;
220
221     return IUnknown_QueryInterface(This->pObject, riid, ppvResult);
222 }
223
224 /******************************************************************************
225  *        PointerMoniker_Reduce
226  ******************************************************************************/
227 static HRESULT WINAPI
228 PointerMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
229                        IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
230 {
231     TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
232
233     if (ppmkReduced==NULL)
234         return E_POINTER;
235
236     PointerMonikerImpl_AddRef(iface);
237
238     *ppmkReduced=iface;
239
240     return MK_S_REDUCED_TO_SELF;
241 }
242 /******************************************************************************
243  *        PointerMoniker_ComposeWith
244  ******************************************************************************/
245 static HRESULT WINAPI
246 PointerMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
247                             BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
248 {
249
250     HRESULT res=S_OK;
251     DWORD mkSys,mkSys2;
252     IEnumMoniker* penumMk=0;
253     IMoniker *pmostLeftMk=0;
254     IMoniker* tempMkComposite=0;
255
256     TRACE("(%p,%d,%p)\n", pmkRight, fOnlyIfNotGeneric, ppmkComposite);
257
258     if ((ppmkComposite==NULL)||(pmkRight==NULL))
259         return E_POINTER;
260
261     *ppmkComposite=0;
262
263     IMoniker_IsSystemMoniker(pmkRight,&mkSys);
264
265     /* If pmkRight is an anti-moniker, the returned moniker is NULL */
266     if(mkSys==MKSYS_ANTIMONIKER)
267         return res;
268
269     else
270         /* if pmkRight is a composite whose leftmost component is an anti-moniker,           */
271         /* the returned moniker is the composite after the leftmost anti-moniker is removed. */
272
273          if(mkSys==MKSYS_GENERICCOMPOSITE){
274
275             res=IMoniker_Enum(pmkRight,TRUE,&penumMk);
276
277             if (FAILED(res))
278                 return res;
279
280             res=IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL);
281
282             IMoniker_IsSystemMoniker(pmostLeftMk,&mkSys2);
283
284             if(mkSys2==MKSYS_ANTIMONIKER){
285
286                 IMoniker_Release(pmostLeftMk);
287
288                 tempMkComposite=iface;
289                 IMoniker_AddRef(iface);
290
291                 while(IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL)==S_OK){
292
293                     res=CreateGenericComposite(tempMkComposite,pmostLeftMk,ppmkComposite);
294
295                     IMoniker_Release(tempMkComposite);
296                     IMoniker_Release(pmostLeftMk);
297
298                     tempMkComposite=*ppmkComposite;
299                     IMoniker_AddRef(tempMkComposite);
300                 }
301                 return res;
302             }
303             else
304                 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
305          }
306          /* If pmkRight is not an anti-moniker, the method combines the two monikers into a generic
307           composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns
308           a NULL moniker and a return value of MK_E_NEEDGENERIC */
309           else
310             if (!fOnlyIfNotGeneric)
311                 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
312
313             else
314                 return MK_E_NEEDGENERIC;
315 }
316
317 /******************************************************************************
318  *        PointerMoniker_Enum
319  ******************************************************************************/
320 static HRESULT WINAPI
321 PointerMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
322 {
323     TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
324
325     if (ppenumMoniker == NULL)
326         return E_POINTER;
327
328     *ppenumMoniker = NULL;
329
330     return S_OK;
331 }
332
333 /******************************************************************************
334  *        PointerMoniker_IsEqual
335  ******************************************************************************/
336 static HRESULT WINAPI
337 PointerMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
338 {
339     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
340     DWORD mkSys;
341
342     TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
343
344     if (pmkOtherMoniker==NULL)
345         return S_FALSE;
346
347     IMoniker_IsSystemMoniker(pmkOtherMoniker,&mkSys);
348
349     if (mkSys==MKSYS_POINTERMONIKER)
350     {
351         PointerMonikerImpl *pOtherMoniker = (PointerMonikerImpl *)pmkOtherMoniker;
352         return This->pObject == pOtherMoniker->pObject ? S_OK : S_FALSE;
353     }
354     else
355         return S_FALSE;
356 }
357
358 /******************************************************************************
359  *        PointerMoniker_Hash
360  ******************************************************************************/
361 static HRESULT WINAPI PointerMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
362 {
363     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
364
365     if (pdwHash==NULL)
366         return E_POINTER;
367
368     *pdwHash = (DWORD)This->pObject;
369
370     return S_OK;
371 }
372
373 /******************************************************************************
374  *        PointerMoniker_IsRunning
375  ******************************************************************************/
376 static HRESULT WINAPI
377 PointerMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
378                           IMoniker* pmkNewlyRunning)
379 {
380     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
381
382     return S_OK;
383 }
384
385 /******************************************************************************
386  *        PointerMoniker_GetTimeOfLastChange
387  ******************************************************************************/
388 static HRESULT WINAPI PointerMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
389                                                    IBindCtx* pbc,
390                                                    IMoniker* pmkToLeft,
391                                                    FILETIME* pAntiTime)
392 {
393     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pAntiTime);
394     return E_NOTIMPL;
395 }
396
397 /******************************************************************************
398  *        PointerMoniker_Inverse
399  ******************************************************************************/
400 static HRESULT WINAPI
401 PointerMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
402 {
403     TRACE("(%p,%p)\n",iface,ppmk);
404
405     return CreateAntiMoniker(ppmk);
406 }
407
408 /******************************************************************************
409  *        PointerMoniker_CommonPrefixWith
410  ******************************************************************************/
411 static HRESULT WINAPI
412 PointerMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
413 {
414     TRACE("(%p, %p)\n", pmkOther, ppmkPrefix);
415
416     *ppmkPrefix = NULL;
417
418     if (PointerMonikerImpl_IsEqual(iface, pmkOther))
419     {
420         IMoniker_AddRef(iface);
421
422         *ppmkPrefix=iface;
423
424         return MK_S_US;
425     }
426     else
427         return MK_E_NOPREFIX;
428 }
429
430 /******************************************************************************
431  *        PointerMoniker_RelativePathTo
432  ******************************************************************************/
433 static HRESULT WINAPI
434 PointerMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
435 {
436     TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
437
438     if (ppmkRelPath==NULL)
439         return E_POINTER;
440
441     *ppmkRelPath = NULL;
442
443     return E_NOTIMPL;
444 }
445
446 /******************************************************************************
447  *        PointerMoniker_GetDisplayName
448  ******************************************************************************/
449 static HRESULT WINAPI
450 PointerMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
451                                IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
452 {
453     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
454
455     if (ppszDisplayName==NULL)
456         return E_POINTER;
457
458     *ppszDisplayName = NULL;
459     return E_NOTIMPL;
460 }
461
462 /******************************************************************************
463  *        PointerMoniker_ParseDisplayName
464  ******************************************************************************/
465 static HRESULT WINAPI
466 PointerMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
467                                  IMoniker* pmkToLeft, LPOLESTR pszDisplayName,
468                                  ULONG* pchEaten, IMoniker** ppmkOut)
469 {
470     PointerMonikerImpl *This = (PointerMonikerImpl *)iface;
471     HRESULT hr;
472     IParseDisplayName *pPDN;
473
474     TRACE("(%p,%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
475
476     if (pmkToLeft)
477         return MK_E_SYNTAX;
478
479     if (!This->pObject)
480         return E_UNEXPECTED;
481
482     hr = IUnknown_QueryInterface(This->pObject, &IID_IParseDisplayName, (void **)&pPDN);
483     if (FAILED(hr))
484         return hr;
485
486     hr = IParseDisplayName_ParseDisplayName(pPDN, pbc, pszDisplayName, pchEaten, ppmkOut);
487     IParseDisplayName_Release(pPDN);
488
489     return hr;
490 }
491
492 /******************************************************************************
493  *        PointerMoniker_IsSystemMoniker
494  ******************************************************************************/
495 static HRESULT WINAPI
496 PointerMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
497 {
498     TRACE("(%p,%p)\n",iface,pwdMksys);
499
500     if (!pwdMksys)
501         return E_POINTER;
502
503     *pwdMksys = MKSYS_POINTERMONIKER;
504
505     return S_OK;
506 }
507
508 /********************************************************************************/
509 /* Virtual function table for the PointerMonikerImpl class which  include IPersist,*/
510 /* IPersistStream and IMoniker functions.                                       */
511 static const IMonikerVtbl VT_PointerMonikerImpl =
512 {
513     PointerMonikerImpl_QueryInterface,
514     PointerMonikerImpl_AddRef,
515     PointerMonikerImpl_Release,
516     PointerMonikerImpl_GetClassID,
517     PointerMonikerImpl_IsDirty,
518     PointerMonikerImpl_Load,
519     PointerMonikerImpl_Save,
520     PointerMonikerImpl_GetSizeMax,
521     PointerMonikerImpl_BindToObject,
522     PointerMonikerImpl_BindToStorage,
523     PointerMonikerImpl_Reduce,
524     PointerMonikerImpl_ComposeWith,
525     PointerMonikerImpl_Enum,
526     PointerMonikerImpl_IsEqual,
527     PointerMonikerImpl_Hash,
528     PointerMonikerImpl_IsRunning,
529     PointerMonikerImpl_GetTimeOfLastChange,
530     PointerMonikerImpl_Inverse,
531     PointerMonikerImpl_CommonPrefixWith,
532     PointerMonikerImpl_RelativePathTo,
533     PointerMonikerImpl_GetDisplayName,
534     PointerMonikerImpl_ParseDisplayName,
535     PointerMonikerImpl_IsSystemMoniker
536 };
537
538 /******************************************************************************
539  *         PointerMoniker_Construct (local function)
540  *******************************************************************************/
541 static void PointerMonikerImpl_Construct(PointerMonikerImpl* This, IUnknown *punk)
542 {
543     TRACE("(%p)\n",This);
544
545     /* Initialize the virtual function table. */
546     This->lpvtbl       = &VT_PointerMonikerImpl;
547     This->ref          = 1;
548     if (punk)
549         IUnknown_AddRef(punk);
550     This->pObject      = punk;
551 }
552
553 /***********************************************************************
554  *           CreatePointerMoniker (OLE32.@)
555  *
556  * Creates a moniker which represents a pointer.
557  *
558  * PARAMS
559  *  punk [I] Pointer to the object to represent.
560  *  ppmk [O] Address that receives the pointer to the created moniker.
561  *
562  * RETURNS
563  *  Success: S_OK.
564  *  Failure: Any HRESULT code.
565  */
566 HRESULT WINAPI CreatePointerMoniker(LPUNKNOWN punk, LPMONIKER *ppmk)
567 {
568     PointerMonikerImpl *This;
569
570     TRACE("(%p, %p)\n", punk, ppmk);
571
572     if (!ppmk)
573         return E_INVALIDARG;
574
575     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
576     if (!This)
577     {
578         *ppmk = NULL;
579         return E_OUTOFMEMORY;
580     }
581
582     PointerMonikerImpl_Construct(This, punk);
583     *ppmk = (IMoniker *)&This->lpvtbl;
584     return S_OK;
585 }
586
587 static HRESULT WINAPI PointerMonikerCF_QueryInterface(LPCLASSFACTORY iface,
588                                                   REFIID riid, LPVOID *ppv)
589 {
590     *ppv = NULL;
591     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
592     {
593         *ppv = iface;
594         IUnknown_AddRef(iface);
595         return S_OK;
596     }
597     return E_NOINTERFACE;
598 }
599
600 static ULONG WINAPI PointerMonikerCF_AddRef(LPCLASSFACTORY iface)
601 {
602     return 2; /* non-heap based object */
603 }
604
605 static ULONG WINAPI PointerMonikerCF_Release(LPCLASSFACTORY iface)
606 {
607     return 1; /* non-heap based object */
608 }
609
610 static HRESULT WINAPI PointerMonikerCF_CreateInstance(LPCLASSFACTORY iface,
611     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
612 {
613     IMoniker *pMoniker;
614     HRESULT  hr;
615
616     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
617
618     *ppv = NULL;
619
620     if (pUnk)
621         return CLASS_E_NOAGGREGATION;
622
623     hr = CreatePointerMoniker(NULL, &pMoniker);
624     if (FAILED(hr))
625         return hr;
626
627         hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
628
629     if (FAILED(hr))
630         IMoniker_Release(pMoniker);
631
632     return hr;
633 }
634
635 static HRESULT WINAPI PointerMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
636 {
637     FIXME("(%d), stub!\n",fLock);
638     return S_OK;
639 }
640
641 static const IClassFactoryVtbl PointerMonikerCFVtbl =
642 {
643     PointerMonikerCF_QueryInterface,
644     PointerMonikerCF_AddRef,
645     PointerMonikerCF_Release,
646     PointerMonikerCF_CreateInstance,
647     PointerMonikerCF_LockServer
648 };
649 static const IClassFactoryVtbl *PointerMonikerCF = &PointerMonikerCFVtbl;
650
651 HRESULT PointerMonikerCF_Create(REFIID riid, LPVOID *ppv)
652 {
653     return IClassFactory_QueryInterface((IClassFactory *)&PointerMonikerCF, riid, ppv);
654 }