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