xref: /reactos/dll/win32/ole32/itemmoniker.c (revision c2c66aff)
1 /*
2  *	                      ItemMonikers implementation
3  *
4  *           Copyright 1999  Noomen Hamza
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 #include "precomp.h"
22 
23 WINE_DEFAULT_DEBUG_CHANNEL(ole);
24 
25 /* ItemMoniker data structure */
26 typedef struct ItemMonikerImpl{
27     IMoniker IMoniker_iface;  /* VTable relative to the IMoniker interface.*/
28     IROTData IROTData_iface;  /* VTable relative to the IROTData interface.*/
29     LONG ref;
30     LPOLESTR itemName; /* item name identified by this ItemMoniker */
31     LPOLESTR itemDelimiter; /* Delimiter string */
32     IUnknown *pMarshal; /* custom marshaler */
33 } ItemMonikerImpl;
34 
35 static inline ItemMonikerImpl *impl_from_IMoniker(IMoniker *iface)
36 {
37     return CONTAINING_RECORD(iface, ItemMonikerImpl, IMoniker_iface);
38 }
39 
40 static inline ItemMonikerImpl *impl_from_IROTData(IROTData *iface)
41 {
42     return CONTAINING_RECORD(iface, ItemMonikerImpl, IROTData_iface);
43 }
44 
45 static HRESULT ItemMonikerImpl_Destroy(ItemMonikerImpl* iface);
46 
47 /*******************************************************************************
48  *        ItemMoniker_QueryInterface
49  *******************************************************************************/
50 static HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
51 {
52     ItemMonikerImpl *This = impl_from_IMoniker(iface);
53 
54     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
55 
56     if (!ppvObject)
57         return E_INVALIDARG;
58 
59     /* Compare the riid with the interface IDs implemented by this object.*/
60     if (IsEqualIID(&IID_IUnknown, riid) ||
61         IsEqualIID(&IID_IPersist, riid) ||
62         IsEqualIID(&IID_IPersistStream, riid) ||
63         IsEqualIID(&IID_IMoniker, riid))
64         *ppvObject = iface;
65     else if (IsEqualIID(&IID_IROTData, riid))
66         *ppvObject = &This->IROTData_iface;
67     else if (IsEqualIID(&IID_IMarshal, riid))
68     {
69         HRESULT hr = S_OK;
70         if (!This->pMarshal)
71             hr = MonikerMarshal_Create(iface, &This->pMarshal);
72         if (hr != S_OK)
73             return hr;
74         return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
75     }
76     else
77     {
78         *ppvObject = NULL;
79         return E_NOINTERFACE;
80     }
81 
82     IMoniker_AddRef(iface);
83     return S_OK;
84 }
85 
86 /******************************************************************************
87  *        ItemMoniker_AddRef
88  ******************************************************************************/
89 static ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface)
90 {
91     ItemMonikerImpl *This = impl_from_IMoniker(iface);
92 
93     TRACE("(%p)\n",This);
94 
95     return InterlockedIncrement(&This->ref);
96 }
97 
98 /******************************************************************************
99  *        ItemMoniker_Release
100  ******************************************************************************/
101 static ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface)
102 {
103     ItemMonikerImpl *This = impl_from_IMoniker(iface);
104     ULONG ref;
105 
106     TRACE("(%p)\n",This);
107 
108     ref = InterlockedDecrement(&This->ref);
109 
110     /* destroy the object if there are no more references to it */
111     if (ref == 0) ItemMonikerImpl_Destroy(This);
112 
113     return ref;
114 }
115 
116 /******************************************************************************
117  *        ItemMoniker_GetClassID
118  ******************************************************************************/
119 static HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
120 {
121     TRACE("(%p,%p)\n",iface,pClassID);
122 
123     if (pClassID==NULL)
124         return E_POINTER;
125 
126     *pClassID = CLSID_ItemMoniker;
127 
128     return S_OK;
129 }
130 
131 /******************************************************************************
132  *        ItemMoniker_IsDirty
133  ******************************************************************************/
134 static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface)
135 {
136     /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
137        method in the OLE-provided moniker interfaces always return S_FALSE because
138        their internal state never changes. */
139 
140     TRACE("(%p)\n",iface);
141 
142     return S_FALSE;
143 }
144 
145 /******************************************************************************
146  *        ItemMoniker_Load
147  ******************************************************************************/
148 static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm)
149 {
150     ItemMonikerImpl *This = impl_from_IMoniker(iface);
151     HRESULT res;
152     DWORD delimiterLength,nameLength,lenW;
153     CHAR *itemNameA,*itemDelimiterA;
154     ULONG bread;
155 
156     TRACE("\n");
157 
158     /* for more details about data read by this function see comments of ItemMonikerImpl_Save function */
159 
160     /* read item delimiter string length + 1 */
161     res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread);
162     if (bread != sizeof(DWORD))
163         return E_FAIL;
164 
165     /* read item delimiter string */
166     if (!(itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength)))
167         return E_OUTOFMEMORY;
168     res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread);
169     if (bread != delimiterLength)
170     {
171         HeapFree( GetProcessHeap(), 0, itemDelimiterA );
172         return E_FAIL;
173     }
174 
175     lenW = MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, NULL, 0 );
176     This->itemDelimiter=HeapReAlloc(GetProcessHeap(),0,This->itemDelimiter,lenW*sizeof(WCHAR));
177     if (!This->itemDelimiter)
178     {
179         HeapFree( GetProcessHeap(), 0, itemDelimiterA );
180         return E_OUTOFMEMORY;
181     }
182     MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, This->itemDelimiter, lenW );
183     HeapFree( GetProcessHeap(), 0, itemDelimiterA );
184 
185     /* read item name string length + 1*/
186     res=IStream_Read(pStm,&nameLength,sizeof(DWORD),&bread);
187     if (bread != sizeof(DWORD))
188         return E_FAIL;
189 
190     /* read item name string */
191     if (!(itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength)))
192         return E_OUTOFMEMORY;
193     res=IStream_Read(pStm,itemNameA,nameLength,&bread);
194     if (bread != nameLength)
195     {
196         HeapFree( GetProcessHeap(), 0, itemNameA );
197         return E_FAIL;
198     }
199 
200     lenW = MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, NULL, 0 );
201     This->itemName=HeapReAlloc(GetProcessHeap(),0,This->itemName,lenW*sizeof(WCHAR));
202     if (!This->itemName)
203     {
204         HeapFree( GetProcessHeap(), 0, itemNameA );
205         return E_OUTOFMEMORY;
206     }
207     MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, This->itemName, lenW );
208     HeapFree( GetProcessHeap(), 0, itemNameA );
209 
210     return res;
211 }
212 
213 /******************************************************************************
214  *        ItemMoniker_Save
215  ******************************************************************************/
216 static HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
217 {
218     ItemMonikerImpl *This = impl_from_IMoniker(iface);
219     HRESULT res;
220     CHAR *itemNameA,*itemDelimiterA;
221 
222     /* data written by this function are : 1) DWORD : size of item delimiter string ('\0' included ) */
223     /*                                    2) String (type A): item delimiter string ('\0' included)          */
224     /*                                    3) DWORD : size of item name string ('\0' included)       */
225     /*                                    4) String (type A): item name string ('\0' included)               */
226 
227     DWORD nameLength = WideCharToMultiByte( CP_ACP, 0, This->itemName, -1, NULL, 0, NULL, NULL);
228     DWORD delimiterLength = WideCharToMultiByte( CP_ACP, 0, This->itemDelimiter, -1, NULL, 0, NULL, NULL);
229     itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength);
230     itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength);
231     WideCharToMultiByte( CP_ACP, 0, This->itemName, -1, itemNameA, nameLength, NULL, NULL);
232     WideCharToMultiByte( CP_ACP, 0, This->itemDelimiter, -1, itemDelimiterA, delimiterLength, NULL, NULL);
233 
234     TRACE("%p, %s\n", pStm, fClearDirty ? "TRUE" : "FALSE");
235 
236     res=IStream_Write(pStm,&delimiterLength,sizeof(DWORD),NULL);
237     res=IStream_Write(pStm,itemDelimiterA,delimiterLength * sizeof(CHAR),NULL);
238     res=IStream_Write(pStm,&nameLength,sizeof(DWORD),NULL);
239     res=IStream_Write(pStm,itemNameA,nameLength * sizeof(CHAR),NULL);
240 
241     HeapFree(GetProcessHeap(), 0, itemNameA);
242     HeapFree(GetProcessHeap(), 0, itemDelimiterA);
243 
244     return res;
245 }
246 
247 /******************************************************************************
248  *        ItemMoniker_GetSizeMax
249  ******************************************************************************/
250 static HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
251 {
252     ItemMonikerImpl *This = impl_from_IMoniker(iface);
253     DWORD delimiterLength=lstrlenW(This->itemDelimiter)+1;
254     DWORD nameLength=lstrlenW(This->itemName)+1;
255 
256     TRACE("(%p,%p)\n",iface,pcbSize);
257 
258     if (!pcbSize)
259         return E_POINTER;
260 
261     /* for more details see ItemMonikerImpl_Save comments */
262 
263     pcbSize->u.LowPart =  sizeof(DWORD) + /* DWORD which contains delimiter length */
264                         delimiterLength*4 + /* item delimiter string */
265                         sizeof(DWORD) + /* DWORD which contains item name length */
266                         nameLength*4 + /* item name string */
267                         18; /* strange, but true */
268     pcbSize->u.HighPart=0;
269 
270     return S_OK;
271 }
272 
273 /******************************************************************************
274  *                  ItemMoniker_BindToObject
275  ******************************************************************************/
276 static HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface,
277                                                    IBindCtx* pbc,
278                                                    IMoniker* pmkToLeft,
279                                                    REFIID riid,
280                                                    VOID** ppvResult)
281 {
282     ItemMonikerImpl *This = impl_from_IMoniker(iface);
283     HRESULT   res;
284     IID    refid=IID_IOleItemContainer;
285     IOleItemContainer *poic=0;
286 
287     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
288 
289     if(ppvResult ==NULL)
290         return E_POINTER;
291 
292     if(pmkToLeft==NULL)
293         return E_INVALIDARG;
294 
295     *ppvResult=0;
296 
297     res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&refid,(void**)&poic);
298 
299     if (SUCCEEDED(res)){
300 
301         res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,riid,ppvResult);
302 
303         IOleItemContainer_Release(poic);
304     }
305 
306     return res;
307 }
308 
309 /******************************************************************************
310  *        ItemMoniker_BindToStorage
311  ******************************************************************************/
312 static HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface,
313                                                     IBindCtx* pbc,
314                                                     IMoniker* pmkToLeft,
315                                                     REFIID riid,
316                                                     VOID** ppvResult)
317 {
318     ItemMonikerImpl *This = impl_from_IMoniker(iface);
319     HRESULT   res;
320     IOleItemContainer *poic=0;
321 
322     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
323 
324     *ppvResult=0;
325 
326     if(pmkToLeft==NULL)
327         return E_INVALIDARG;
328 
329     res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic);
330 
331     if (SUCCEEDED(res)){
332 
333         res=IOleItemContainer_GetObjectStorage(poic,This->itemName,pbc,riid,ppvResult);
334 
335         IOleItemContainer_Release(poic);
336     }
337 
338     return res;
339 }
340 
341 /******************************************************************************
342  *        ItemMoniker_Reduce
343  ******************************************************************************/
344 static HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface,
345                                              IBindCtx* pbc,
346                                              DWORD dwReduceHowFar,
347                                              IMoniker** ppmkToLeft,
348                                              IMoniker** ppmkReduced)
349 {
350     TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
351 
352     if (ppmkReduced==NULL)
353         return E_POINTER;
354 
355     ItemMonikerImpl_AddRef(iface);
356 
357     *ppmkReduced=iface;
358 
359     return MK_S_REDUCED_TO_SELF;
360 }
361 /******************************************************************************
362  *        ItemMoniker_ComposeWith
363  ******************************************************************************/
364 static HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface,
365                                                   IMoniker* pmkRight,
366                                                   BOOL fOnlyIfNotGeneric,
367                                                   IMoniker** ppmkComposite)
368 {
369     HRESULT res=S_OK;
370     DWORD mkSys,mkSys2;
371     IEnumMoniker* penumMk=0;
372     IMoniker *pmostLeftMk=0;
373     IMoniker* tempMkComposite=0;
374 
375     TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
376 
377     if ((ppmkComposite==NULL)||(pmkRight==NULL))
378 	return E_POINTER;
379 
380     *ppmkComposite=0;
381 
382     IMoniker_IsSystemMoniker(pmkRight,&mkSys);
383 
384     /* If pmkRight is an anti-moniker, the returned moniker is NULL */
385     if(mkSys==MKSYS_ANTIMONIKER)
386         return res;
387 
388     else
389         /* if pmkRight is a composite whose leftmost component is an anti-moniker,           */
390         /* the returned moniker is the composite after the leftmost anti-moniker is removed. */
391 
392          if(mkSys==MKSYS_GENERICCOMPOSITE){
393 
394             res=IMoniker_Enum(pmkRight,TRUE,&penumMk);
395 
396             if (FAILED(res))
397                 return res;
398 
399             res=IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL);
400 
401             IMoniker_IsSystemMoniker(pmostLeftMk,&mkSys2);
402 
403             if(mkSys2==MKSYS_ANTIMONIKER){
404 
405                 IMoniker_Release(pmostLeftMk);
406 
407                 tempMkComposite=iface;
408                 IMoniker_AddRef(iface);
409 
410                 while(IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL)==S_OK){
411 
412                     res=CreateGenericComposite(tempMkComposite,pmostLeftMk,ppmkComposite);
413 
414                     IMoniker_Release(tempMkComposite);
415                     IMoniker_Release(pmostLeftMk);
416 
417                     tempMkComposite=*ppmkComposite;
418                     IMoniker_AddRef(tempMkComposite);
419                 }
420                 return res;
421             }
422             else
423                 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
424          }
425          /* If pmkRight is not an anti-moniker, the method combines the two monikers into a generic
426           composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns
427           a NULL moniker and a return value of MK_E_NEEDGENERIC */
428           else
429             if (!fOnlyIfNotGeneric)
430                 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
431 
432             else
433                 return MK_E_NEEDGENERIC;
434 }
435 
436 /******************************************************************************
437  *        ItemMoniker_Enum
438  ******************************************************************************/
439 static HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
440 {
441     TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
442 
443     if (ppenumMoniker == NULL)
444         return E_POINTER;
445 
446     *ppenumMoniker = NULL;
447 
448     return S_OK;
449 }
450 
451 /******************************************************************************
452  *        ItemMoniker_IsEqual
453  ******************************************************************************/
454 static HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
455 {
456 
457     CLSID clsid;
458     LPOLESTR dispName1,dispName2;
459     IBindCtx* bind;
460     HRESULT res = S_FALSE;
461 
462     TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
463 
464     if (!pmkOtherMoniker) return S_FALSE;
465 
466 
467     /* check if both are ItemMoniker */
468     if(FAILED (IMoniker_GetClassID(pmkOtherMoniker,&clsid))) return S_FALSE;
469     if(!IsEqualCLSID(&clsid,&CLSID_ItemMoniker)) return S_FALSE;
470 
471     /* check if both displaynames are the same */
472     if(SUCCEEDED ((res = CreateBindCtx(0,&bind)))) {
473         if(SUCCEEDED (IMoniker_GetDisplayName(iface,bind,NULL,&dispName1))) {
474 	    if(SUCCEEDED (IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&dispName2))) {
475                 if(lstrcmpW(dispName1,dispName2)==0) res = S_OK;
476                 CoTaskMemFree(dispName2);
477             }
478             CoTaskMemFree(dispName1);
479 	}
480     }
481     return res;
482 }
483 
484 /******************************************************************************
485  *        ItemMoniker_Hash
486  ******************************************************************************/
487 static HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
488 {
489     ItemMonikerImpl *This = impl_from_IMoniker(iface);
490     DWORD h = 0;
491     int  i,len;
492     int  off = 0;
493     LPOLESTR val;
494 
495     if (pdwHash==NULL)
496         return E_POINTER;
497 
498     val =  This->itemName;
499     len = lstrlenW(val);
500 
501     for (i = len ; i > 0; i--)
502         h = (h * 3) ^ toupperW(val[off++]);
503 
504     *pdwHash=h;
505 
506     return S_OK;
507 }
508 
509 /******************************************************************************
510  *        ItemMoniker_IsRunning
511  ******************************************************************************/
512 static HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface,
513                                                 IBindCtx* pbc,
514                                                 IMoniker* pmkToLeft,
515                                                 IMoniker* pmkNewlyRunning)
516 {
517     ItemMonikerImpl *This = impl_from_IMoniker(iface);
518     IRunningObjectTable* rot;
519     HRESULT res;
520     IOleItemContainer *poic=0;
521 
522     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
523 
524     /* If pmkToLeft is NULL, this method returns TRUE if pmkNewlyRunning is non-NULL and is equal to this */
525     /* moniker. Otherwise, the method checks the ROT to see whether this moniker is running.              */
526     if (pmkToLeft==NULL)
527         if ((pmkNewlyRunning!=NULL)&&(IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK))
528             return S_OK;
529         else {
530             if (pbc==NULL)
531                 return E_INVALIDARG;
532 
533             res=IBindCtx_GetRunningObjectTable(pbc,&rot);
534 
535             if (FAILED(res))
536                 return res;
537 
538             res = IRunningObjectTable_IsRunning(rot,iface);
539 
540             IRunningObjectTable_Release(rot);
541         }
542     else{
543 
544         /* If pmkToLeft is non-NULL, the method calls IMoniker::BindToObject on the pmkToLeft parameter,         */
545         /* requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::IsRunning,*/
546         /* passing the string contained within this moniker. */
547 
548         res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic);
549 
550         if (SUCCEEDED(res)){
551 
552             res=IOleItemContainer_IsRunning(poic,This->itemName);
553 
554             IOleItemContainer_Release(poic);
555         }
556     }
557 
558     return res;
559 }
560 
561 /******************************************************************************
562  *        ItemMoniker_GetTimeOfLastChange
563  ******************************************************************************/
564 static HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
565                                                           IBindCtx* pbc,
566                                                           IMoniker* pmkToLeft,
567                                                           FILETIME* pItemTime)
568 {
569     IRunningObjectTable* rot;
570     HRESULT res;
571     IMoniker *compositeMk;
572 
573     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pItemTime);
574 
575     if (pItemTime==NULL)
576         return E_INVALIDARG;
577 
578     /* If pmkToLeft is NULL, this method returns MK_E_NOTBINDABLE */
579     if (pmkToLeft==NULL)
580 
581         return MK_E_NOTBINDABLE;
582     else {
583 
584         /* Otherwise, the method creates a composite of pmkToLeft and this moniker and uses the ROT to access  */
585         /* the time of last change. If the object is not in the ROT, the method calls                          */
586         /* IMoniker::GetTimeOfLastChange on the pmkToLeft parameter.                                            */
587 
588         res=CreateGenericComposite(pmkToLeft,iface,&compositeMk);
589         if (FAILED(res))
590             return res;
591 
592         res=IBindCtx_GetRunningObjectTable(pbc,&rot);
593         if (FAILED(res)) {
594             IMoniker_Release(compositeMk);
595             return res;
596         }
597 
598         if (IRunningObjectTable_GetTimeOfLastChange(rot,compositeMk,pItemTime)!=S_OK)
599 
600             res=IMoniker_GetTimeOfLastChange(pmkToLeft,pbc,NULL,pItemTime);
601 
602         IMoniker_Release(compositeMk);
603     }
604 
605     return res;
606 }
607 
608 /******************************************************************************
609  *        ItemMoniker_Inverse
610  ******************************************************************************/
611 static HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
612 {
613     TRACE("(%p,%p)\n",iface,ppmk);
614 
615     if (ppmk==NULL)
616         return E_POINTER;
617 
618     return CreateAntiMoniker(ppmk);
619 }
620 
621 /******************************************************************************
622  *        ItemMoniker_CommonPrefixWith
623  ******************************************************************************/
624 static HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
625 {
626     DWORD mkSys;
627 
628     TRACE("(%p,%p)\n", pmkOther, ppmkPrefix);
629 
630     IMoniker_IsSystemMoniker(pmkOther,&mkSys);
631     /* If the other moniker is an item moniker that is equal to this moniker, this method sets *ppmkPrefix */
632     /* to this moniker and returns MK_S_US */
633 
634     if((mkSys==MKSYS_ITEMMONIKER) && (IMoniker_IsEqual(iface,pmkOther)==S_OK) ){
635 
636         *ppmkPrefix=iface;
637 
638         IMoniker_AddRef(iface);
639 
640         return MK_S_US;
641     }
642     else
643         /* otherwise, the method calls the MonikerCommonPrefixWith function. This function correctly handles */
644         /* the case where the other moniker is a generic composite. */
645         return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
646 }
647 
648 /******************************************************************************
649  *        ItemMoniker_RelativePathTo
650  ******************************************************************************/
651 static HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
652 {
653     TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
654 
655     if (ppmkRelPath==NULL)
656         return E_POINTER;
657 
658     *ppmkRelPath=0;
659 
660     return MK_E_NOTBINDABLE;
661 }
662 
663 /******************************************************************************
664  *        ItemMoniker_GetDisplayName
665  ******************************************************************************/
666 static HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface,
667                                                      IBindCtx* pbc,
668                                                      IMoniker* pmkToLeft,
669                                                      LPOLESTR *ppszDisplayName)
670 {
671     ItemMonikerImpl *This = impl_from_IMoniker(iface);
672 
673     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
674 
675     if (ppszDisplayName==NULL)
676         return E_POINTER;
677 
678     if (pmkToLeft!=NULL){
679         return E_INVALIDARG;
680     }
681 
682     *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(lstrlenW(This->itemDelimiter)+lstrlenW(This->itemName)+1));
683 
684     if (*ppszDisplayName==NULL)
685         return E_OUTOFMEMORY;
686 
687     lstrcpyW(*ppszDisplayName,This->itemDelimiter);
688     lstrcatW(*ppszDisplayName,This->itemName);
689 
690     TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
691 
692     return S_OK;
693 }
694 
695 /******************************************************************************
696  *        ItemMoniker_ParseDisplayName
697  ******************************************************************************/
698 static HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface,
699                                                        IBindCtx* pbc,
700                                                        IMoniker* pmkToLeft,
701                                                        LPOLESTR pszDisplayName,
702                                                        ULONG* pchEaten,
703                                                        IMoniker** ppmkOut)
704 {
705     ItemMonikerImpl *This = impl_from_IMoniker(iface);
706     IOleItemContainer* poic=0;
707     IParseDisplayName* ppdn=0;
708     LPOLESTR displayName;
709     HRESULT res;
710 
711     TRACE("%s\n", debugstr_w(pszDisplayName));
712 
713     /* If pmkToLeft is NULL, this method returns MK_E_SYNTAX */
714     if (pmkToLeft==NULL)
715 
716         return MK_E_SYNTAX;
717 
718     else{
719         /* Otherwise, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an */
720         /* IParseDisplayName interface pointer to the object identified by the moniker, and passes the display */
721         /* name to IParseDisplayName::ParseDisplayName */
722         res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic);
723 
724         if (SUCCEEDED(res)){
725 
726             res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,&IID_IParseDisplayName,(void**)&ppdn);
727 
728             res=IMoniker_GetDisplayName(iface,pbc,NULL,&displayName);
729 
730             res=IParseDisplayName_ParseDisplayName(ppdn,pbc,displayName,pchEaten,ppmkOut);
731 
732             IOleItemContainer_Release(poic);
733             IParseDisplayName_Release(ppdn);
734         }
735     }
736     return res;
737 }
738 
739 /******************************************************************************
740  *        ItemMoniker_IsSystemMoniker
741  ******************************************************************************/
742 static HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
743 {
744     TRACE("(%p,%p)\n",iface,pwdMksys);
745 
746     if (!pwdMksys)
747         return E_POINTER;
748 
749     (*pwdMksys)=MKSYS_ITEMMONIKER;
750 
751     return S_OK;
752 }
753 
754 /*******************************************************************************
755  *        ItemMonikerIROTData_QueryInterface
756  *******************************************************************************/
757 static HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
758                                                             void **ppvObject)
759 {
760 
761     ItemMonikerImpl *This = impl_from_IROTData(iface);
762 
763     TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
764 
765     return ItemMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
766 }
767 
768 /***********************************************************************
769  *        ItemMonikerIROTData_AddRef
770  */
771 static ULONG   WINAPI ItemMonikerROTDataImpl_AddRef(IROTData *iface)
772 {
773     ItemMonikerImpl *This = impl_from_IROTData(iface);
774 
775     TRACE("(%p)\n",iface);
776 
777     return ItemMonikerImpl_AddRef(&This->IMoniker_iface);
778 }
779 
780 /***********************************************************************
781  *        ItemMonikerIROTData_Release
782  */
783 static ULONG   WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface)
784 {
785     ItemMonikerImpl *This = impl_from_IROTData(iface);
786 
787     TRACE("(%p)\n",iface);
788 
789     return ItemMonikerImpl_Release(&This->IMoniker_iface);
790 }
791 
792 /******************************************************************************
793  *        ItemMonikerIROTData_GetComparisonData
794  ******************************************************************************/
795 static HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface,
796                                                                BYTE* pbData,
797                                                                ULONG cbMax,
798                                                                ULONG* pcbData)
799 {
800     ItemMonikerImpl *This = impl_from_IROTData(iface);
801     int len = (strlenW(This->itemName)+1);
802     int i;
803     LPWSTR pszItemName;
804     LPWSTR pszItemDelimiter;
805 
806     TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
807 
808     *pcbData = sizeof(CLSID) + sizeof(WCHAR) + len * sizeof(WCHAR);
809     if (cbMax < *pcbData)
810         return E_OUTOFMEMORY;
811 
812     /* write CLSID */
813     memcpy(pbData, &CLSID_ItemMoniker, sizeof(CLSID));
814     /* write delimiter */
815     pszItemDelimiter = (LPWSTR)(pbData+sizeof(CLSID));
816     *pszItemDelimiter = *This->itemDelimiter;
817     /* write name */
818     pszItemName = pszItemDelimiter + 1;
819     for (i = 0; i < len; i++)
820         pszItemName[i] = toupperW(This->itemName[i]);
821 
822     return S_OK;
823 }
824 
825 /********************************************************************************/
826 /* Virtual function table for the ItemMonikerImpl class which  include IPersist,*/
827 /* IPersistStream and IMoniker functions.                                       */
828 static const IMonikerVtbl VT_ItemMonikerImpl =
829     {
830     ItemMonikerImpl_QueryInterface,
831     ItemMonikerImpl_AddRef,
832     ItemMonikerImpl_Release,
833     ItemMonikerImpl_GetClassID,
834     ItemMonikerImpl_IsDirty,
835     ItemMonikerImpl_Load,
836     ItemMonikerImpl_Save,
837     ItemMonikerImpl_GetSizeMax,
838     ItemMonikerImpl_BindToObject,
839     ItemMonikerImpl_BindToStorage,
840     ItemMonikerImpl_Reduce,
841     ItemMonikerImpl_ComposeWith,
842     ItemMonikerImpl_Enum,
843     ItemMonikerImpl_IsEqual,
844     ItemMonikerImpl_Hash,
845     ItemMonikerImpl_IsRunning,
846     ItemMonikerImpl_GetTimeOfLastChange,
847     ItemMonikerImpl_Inverse,
848     ItemMonikerImpl_CommonPrefixWith,
849     ItemMonikerImpl_RelativePathTo,
850     ItemMonikerImpl_GetDisplayName,
851     ItemMonikerImpl_ParseDisplayName,
852     ItemMonikerImpl_IsSystemMoniker
853 };
854 
855 /********************************************************************************/
856 /* Virtual function table for the IROTData class.                               */
857 static const IROTDataVtbl VT_ROTDataImpl =
858 {
859     ItemMonikerROTDataImpl_QueryInterface,
860     ItemMonikerROTDataImpl_AddRef,
861     ItemMonikerROTDataImpl_Release,
862     ItemMonikerROTDataImpl_GetComparisonData
863 };
864 
865 /******************************************************************************
866  *         ItemMoniker_Construct (local function)
867  *******************************************************************************/
868 static HRESULT ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem)
869 {
870 
871     int sizeStr1=lstrlenW(lpszItem), sizeStr2;
872     static const OLECHAR emptystr[1];
873     LPCOLESTR	delim;
874 
875     TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszDelim),debugstr_w(lpszItem));
876 
877     /* Initialize the virtual function table. */
878     This->IMoniker_iface.lpVtbl = &VT_ItemMonikerImpl;
879     This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
880     This->ref          = 0;
881     This->pMarshal     = NULL;
882 
883     This->itemName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr1+1));
884     if (!This->itemName)
885 	return E_OUTOFMEMORY;
886     lstrcpyW(This->itemName,lpszItem);
887 
888     if (!lpszDelim)
889 	FIXME("lpszDelim is NULL. Using empty string which is possibly wrong.\n");
890 
891     delim = lpszDelim ? lpszDelim : emptystr;
892 
893     sizeStr2=lstrlenW(delim);
894     This->itemDelimiter=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr2+1));
895     if (!This->itemDelimiter) {
896 	HeapFree(GetProcessHeap(),0,This->itemName);
897 	return E_OUTOFMEMORY;
898     }
899     lstrcpyW(This->itemDelimiter,delim);
900     return S_OK;
901 }
902 
903 /******************************************************************************
904  *        ItemMoniker_Destroy (local function)
905  *******************************************************************************/
906 static HRESULT ItemMonikerImpl_Destroy(ItemMonikerImpl* This)
907 {
908     TRACE("(%p)\n",This);
909 
910     if (This->pMarshal) IUnknown_Release(This->pMarshal);
911     HeapFree(GetProcessHeap(),0,This->itemName);
912     HeapFree(GetProcessHeap(),0,This->itemDelimiter);
913     HeapFree(GetProcessHeap(),0,This);
914 
915     return S_OK;
916 }
917 
918 /******************************************************************************
919  *        CreateItemMoniker	[OLE32.@]
920  ******************************************************************************/
921 HRESULT WINAPI CreateItemMoniker(LPCOLESTR lpszDelim, LPCOLESTR  lpszItem, IMoniker **ppmk)
922 {
923     ItemMonikerImpl* newItemMoniker;
924     HRESULT        hr;
925 
926     TRACE("(%s,%s,%p)\n",debugstr_w(lpszDelim),debugstr_w(lpszItem),ppmk);
927 
928     newItemMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ItemMonikerImpl));
929 
930     if (!newItemMoniker)
931         return STG_E_INSUFFICIENTMEMORY;
932 
933     hr = ItemMonikerImpl_Construct(newItemMoniker,lpszDelim,lpszItem);
934 
935     if (FAILED(hr)){
936         HeapFree(GetProcessHeap(),0,newItemMoniker);
937         return hr;
938     }
939 
940     return ItemMonikerImpl_QueryInterface(&newItemMoniker->IMoniker_iface,&IID_IMoniker,
941                                           (void**)ppmk);
942 }
943 
944 HRESULT WINAPI ItemMoniker_CreateInstance(IClassFactory *iface,
945     IUnknown *pUnk, REFIID riid, void **ppv)
946 {
947     ItemMonikerImpl* newItemMoniker;
948     HRESULT  hr;
949     static const WCHAR wszEmpty[] = { 0 };
950 
951     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
952 
953     *ppv = NULL;
954 
955     if (pUnk)
956         return CLASS_E_NOAGGREGATION;
957 
958     newItemMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ItemMonikerImpl));
959     if (!newItemMoniker)
960         return E_OUTOFMEMORY;
961 
962     hr = ItemMonikerImpl_Construct(newItemMoniker, wszEmpty, wszEmpty);
963 
964     if (SUCCEEDED(hr))
965         hr = ItemMonikerImpl_QueryInterface(&newItemMoniker->IMoniker_iface, riid, ppv);
966     if (FAILED(hr))
967         HeapFree(GetProcessHeap(),0,newItemMoniker);
968 
969     return hr;
970 }
971