xref: /reactos/dll/win32/ole32/classmoniker.c (revision 1734f297)
1 /*
2  *	                      Class Monikers
3  *
4  *           Copyright 1999  Noomen Hamza
5  *           Copyright 2005-2007  Robert Shearman
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 <assert.h>
23 #include <stdarg.h>
24 #include <string.h>
25 
26 #define COBJMACROS
27 
28 #include "winerror.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "wine/debug.h"
33 #include "ole2.h"
34 #include "moniker.h"
35 
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
37 
38 #define CHARS_IN_GUID 39
39 
40 /* ClassMoniker data structure */
41 typedef struct ClassMoniker
42 {
43     IMoniker IMoniker_iface;
44     IROTData IROTData_iface;
45     LONG ref;
46     CLSID clsid; /* clsid identified by this moniker */
47     IUnknown *pMarshal; /* custom marshaler */
48 } ClassMoniker;
49 
50 static inline ClassMoniker *impl_from_IMoniker(IMoniker *iface)
51 {
52     return CONTAINING_RECORD(iface, ClassMoniker, IMoniker_iface);
53 }
54 
55 static inline ClassMoniker *impl_from_IROTData(IROTData *iface)
56 {
57     return CONTAINING_RECORD(iface, ClassMoniker, IROTData_iface);
58 }
59 
60 /*******************************************************************************
61  *        ClassMoniker_QueryInterface
62  *******************************************************************************/
63 static HRESULT WINAPI ClassMoniker_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
64 {
65     ClassMoniker *This = impl_from_IMoniker(iface);
66 
67     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
68 
69     /* Perform a sanity check on the parameters.*/
70     if (!ppvObject)
71         return E_POINTER;
72 
73     /* Initialize the return parameter */
74     *ppvObject = 0;
75 
76     /* Compare the riid with the interface IDs implemented by this object.*/
77     if (IsEqualIID(&IID_IUnknown, riid) ||
78         IsEqualIID(&IID_IPersist, riid) ||
79         IsEqualIID(&IID_IPersistStream, riid) ||
80         IsEqualIID(&IID_IMoniker, riid))
81     {
82         *ppvObject = iface;
83     }
84     else if (IsEqualIID(&IID_IROTData, riid))
85         *ppvObject = &This->IROTData_iface;
86     else if (IsEqualIID(&IID_IMarshal, riid))
87     {
88         HRESULT hr = S_OK;
89         if (!This->pMarshal)
90             hr = MonikerMarshal_Create(iface, &This->pMarshal);
91         if (hr != S_OK)
92             return hr;
93         return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
94     }
95 
96     /* Check that we obtained an interface.*/
97     if (!*ppvObject)
98         return E_NOINTERFACE;
99 
100     /* Query Interface always increases the reference count by one when it is successful */
101     IMoniker_AddRef(iface);
102 
103     return S_OK;
104 }
105 
106 /******************************************************************************
107  *        ClassMoniker_AddRef
108  ******************************************************************************/
109 static ULONG WINAPI ClassMoniker_AddRef(IMoniker* iface)
110 {
111     ClassMoniker *This = impl_from_IMoniker(iface);
112 
113     TRACE("(%p)\n",This);
114 
115     return InterlockedIncrement(&This->ref);
116 }
117 
118 /******************************************************************************
119  *        ClassMoniker_Release
120  ******************************************************************************/
121 static ULONG WINAPI ClassMoniker_Release(IMoniker* iface)
122 {
123     ClassMoniker *This = impl_from_IMoniker(iface);
124     ULONG ref;
125 
126     TRACE("(%p)\n",This);
127 
128     ref = InterlockedDecrement(&This->ref);
129 
130     /* destroy the object if there are no more references to it */
131     if (ref == 0)
132     {
133         if (This->pMarshal) IUnknown_Release(This->pMarshal);
134         HeapFree(GetProcessHeap(),0,This);
135     }
136 
137     return ref;
138 }
139 
140 /******************************************************************************
141  *        ClassMoniker_GetClassID
142  ******************************************************************************/
143 static HRESULT WINAPI ClassMoniker_GetClassID(IMoniker* iface,CLSID *pClassID)
144 {
145     TRACE("(%p,%p),stub!\n",iface,pClassID);
146 
147     if (pClassID==NULL)
148         return E_POINTER;
149 
150     *pClassID = CLSID_ClassMoniker;
151 
152     return S_OK;
153 }
154 
155 /******************************************************************************
156  *        ClassMoniker_IsDirty
157  ******************************************************************************/
158 static HRESULT WINAPI ClassMoniker_IsDirty(IMoniker* iface)
159 {
160     /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
161        method in the OLE-provided moniker interfaces always return S_FALSE because
162        their internal state never changes. */
163 
164     TRACE("(%p)\n",iface);
165 
166     return S_FALSE;
167 }
168 
169 /******************************************************************************
170  *        ClassMoniker_Load
171  ******************************************************************************/
172 static HRESULT WINAPI ClassMoniker_Load(IMoniker* iface,IStream* pStm)
173 {
174     ClassMoniker *This = impl_from_IMoniker(iface);
175     HRESULT hr;
176     DWORD zero;
177 
178     TRACE("(%p)\n", pStm);
179 
180     hr = IStream_Read(pStm, &This->clsid, sizeof(This->clsid), NULL);
181     if (hr != S_OK) return STG_E_READFAULT;
182 
183     hr = IStream_Read(pStm, &zero, sizeof(zero), NULL);
184     if ((hr != S_OK) || (zero != 0)) return STG_E_READFAULT;
185 
186     return S_OK;
187 }
188 
189 /******************************************************************************
190  *        ClassMoniker_Save
191  ******************************************************************************/
192 static HRESULT WINAPI ClassMoniker_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
193 {
194     ClassMoniker *This = impl_from_IMoniker(iface);
195     HRESULT hr;
196     DWORD zero = 0;
197 
198     TRACE("(%p, %s)\n", pStm, fClearDirty ? "TRUE" : "FALSE");
199 
200     hr = IStream_Write(pStm, &This->clsid, sizeof(This->clsid), NULL);
201     if (FAILED(hr)) return hr;
202 
203     return IStream_Write(pStm, &zero, sizeof(zero), NULL);
204 }
205 
206 /******************************************************************************
207  *        ClassMoniker_GetSizeMax
208  ******************************************************************************/
209 static HRESULT WINAPI ClassMoniker_GetSizeMax(IMoniker* iface,
210                                           ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */
211 {
212     TRACE("(%p)\n", pcbSize);
213 
214     pcbSize->QuadPart = sizeof(CLSID) + sizeof(DWORD);
215 
216     return S_OK;
217 }
218 
219 /******************************************************************************
220  *                  ClassMoniker_BindToObject
221  ******************************************************************************/
222 static HRESULT WINAPI ClassMoniker_BindToObject(IMoniker* iface,
223                                             IBindCtx* pbc,
224                                             IMoniker* pmkToLeft,
225                                             REFIID riid,
226                                             VOID** ppvResult)
227 {
228     ClassMoniker *This = impl_from_IMoniker(iface);
229     BIND_OPTS2 bindopts;
230     IClassActivator *pActivator;
231     HRESULT hr;
232 
233     TRACE("(%p, %p, %s, %p)\n", pbc, pmkToLeft, debugstr_guid(riid), ppvResult);
234 
235     bindopts.cbStruct = sizeof(bindopts);
236     IBindCtx_GetBindOptions(pbc, (BIND_OPTS *)&bindopts);
237 
238     if (!pmkToLeft)
239         return CoGetClassObject(&This->clsid, bindopts.dwClassContext, NULL,
240                                 riid, ppvResult);
241     else
242     {
243         hr = IMoniker_BindToObject(pmkToLeft, pbc, NULL, &IID_IClassActivator,
244                                    (void **)&pActivator);
245         if (FAILED(hr)) return hr;
246 
247         hr = IClassActivator_GetClassObject(pActivator, &This->clsid,
248                                             bindopts.dwClassContext,
249                                             bindopts.locale, riid, ppvResult);
250 
251         IClassActivator_Release(pActivator);
252 
253         return hr;
254     }
255 }
256 
257 /******************************************************************************
258  *        ClassMoniker_BindToStorage
259  ******************************************************************************/
260 static HRESULT WINAPI ClassMoniker_BindToStorage(IMoniker* iface,
261                                              IBindCtx* pbc,
262                                              IMoniker* pmkToLeft,
263                                              REFIID riid,
264                                              VOID** ppvResult)
265 {
266     TRACE("(%p, %p, %s, %p)\n", pbc, pmkToLeft, debugstr_guid(riid), ppvResult);
267     return IMoniker_BindToObject(iface, pbc, pmkToLeft, riid, ppvResult);
268 }
269 
270 /******************************************************************************
271  *        ClassMoniker_Reduce
272  ******************************************************************************/
273 static HRESULT WINAPI ClassMoniker_Reduce(IMoniker* iface,
274                                       IBindCtx* pbc,
275                                       DWORD dwReduceHowFar,
276                                       IMoniker** ppmkToLeft,
277                                       IMoniker** ppmkReduced)
278 {
279     TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
280 
281     if (!ppmkReduced)
282         return E_POINTER;
283 
284     IMoniker_AddRef(iface);
285 
286     *ppmkReduced = iface;
287 
288     return MK_S_REDUCED_TO_SELF;
289 }
290 /******************************************************************************
291  *        ClassMoniker_ComposeWith
292  ******************************************************************************/
293 static HRESULT WINAPI ClassMoniker_ComposeWith(IMoniker* iface,
294                                            IMoniker* pmkRight,
295                                            BOOL fOnlyIfNotGeneric,
296                                            IMoniker** ppmkComposite)
297 {
298     HRESULT res=S_OK;
299     DWORD mkSys,mkSys2;
300     IEnumMoniker* penumMk=0;
301     IMoniker *pmostLeftMk=0;
302     IMoniker* tempMkComposite=0;
303 
304     TRACE("(%p,%d,%p)\n", pmkRight, fOnlyIfNotGeneric, ppmkComposite);
305 
306     if ((ppmkComposite==NULL)||(pmkRight==NULL))
307 	return E_POINTER;
308 
309     *ppmkComposite=0;
310 
311     IMoniker_IsSystemMoniker(pmkRight,&mkSys);
312 
313     /* If pmkRight is an anti-moniker, the returned moniker is NULL */
314     if(mkSys==MKSYS_ANTIMONIKER)
315         return res;
316 
317     else
318         /* if pmkRight is a composite whose leftmost component is an anti-moniker,           */
319         /* the returned moniker is the composite after the leftmost anti-moniker is removed. */
320 
321          if(mkSys==MKSYS_GENERICCOMPOSITE){
322 
323             res=IMoniker_Enum(pmkRight,TRUE,&penumMk);
324 
325             if (FAILED(res))
326                 return res;
327 
328             res=IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL);
329 
330             IMoniker_IsSystemMoniker(pmostLeftMk,&mkSys2);
331 
332             if(mkSys2==MKSYS_ANTIMONIKER){
333 
334                 IMoniker_Release(pmostLeftMk);
335 
336                 tempMkComposite=iface;
337                 IMoniker_AddRef(iface);
338 
339                 while(IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL)==S_OK){
340 
341                     res=CreateGenericComposite(tempMkComposite,pmostLeftMk,ppmkComposite);
342 
343                     IMoniker_Release(tempMkComposite);
344                     IMoniker_Release(pmostLeftMk);
345 
346                     tempMkComposite=*ppmkComposite;
347                     IMoniker_AddRef(tempMkComposite);
348                 }
349                 return res;
350             }
351             else
352                 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
353          }
354          /* If pmkRight is not an anti-moniker, the method combines the two monikers into a generic
355           composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns
356           a NULL moniker and a return value of MK_E_NEEDGENERIC */
357           else
358             if (!fOnlyIfNotGeneric)
359                 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
360 
361             else
362                 return MK_E_NEEDGENERIC;
363 }
364 
365 /******************************************************************************
366  *        ClassMoniker_Enum
367  ******************************************************************************/
368 static HRESULT WINAPI ClassMoniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
369 {
370     TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
371 
372     if (ppenumMoniker == NULL)
373         return E_POINTER;
374 
375     *ppenumMoniker = NULL;
376 
377     return S_OK;
378 }
379 
380 /******************************************************************************
381  *        ClassMoniker_IsEqual
382  ******************************************************************************/
383 static HRESULT WINAPI ClassMoniker_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
384 {
385 
386     CLSID clsid;
387     LPOLESTR dispName1,dispName2;
388     IBindCtx* bind;
389     HRESULT res = S_FALSE;
390 
391     TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
392 
393     if (!pmkOtherMoniker) return S_FALSE;
394 
395 
396     /* check if both are ClassMoniker */
397     if(FAILED (IMoniker_GetClassID(pmkOtherMoniker,&clsid))) return S_FALSE;
398     if(!IsEqualCLSID(&clsid,&CLSID_ClassMoniker)) return S_FALSE;
399 
400     /* check if both displaynames are the same */
401     if(SUCCEEDED ((res = CreateBindCtx(0,&bind)))) {
402         if(SUCCEEDED (IMoniker_GetDisplayName(iface,bind,NULL,&dispName1))) {
403 	    if(SUCCEEDED (IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&dispName2))) {
404                 if(wcscmp(dispName1,dispName2)==0) res = S_OK;
405                 CoTaskMemFree(dispName2);
406             }
407             CoTaskMemFree(dispName1);
408 	}
409     }
410     return res;
411 }
412 
413 /******************************************************************************
414  *        ClassMoniker_Hash
415  ******************************************************************************/
416 static HRESULT WINAPI ClassMoniker_Hash(IMoniker* iface,DWORD* pdwHash)
417 {
418     ClassMoniker *This = impl_from_IMoniker(iface);
419 
420     TRACE("(%p)\n", pdwHash);
421 
422     *pdwHash = This->clsid.Data1;
423 
424     return S_OK;
425 }
426 
427 /******************************************************************************
428  *        ClassMoniker_IsRunning
429  ******************************************************************************/
430 static HRESULT WINAPI ClassMoniker_IsRunning(IMoniker* iface,
431                                          IBindCtx* pbc,
432                                          IMoniker* pmkToLeft,
433                                          IMoniker* pmkNewlyRunning)
434 {
435     TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pmkNewlyRunning);
436 
437     /* as in native */
438     return E_NOTIMPL;
439 }
440 
441 /******************************************************************************
442  *        ClassMoniker_GetTimeOfLastChange
443  ******************************************************************************/
444 static HRESULT WINAPI ClassMoniker_GetTimeOfLastChange(IMoniker* iface,
445                                                    IBindCtx* pbc,
446                                                    IMoniker* pmkToLeft,
447                                                    FILETIME* pItemTime)
448 {
449     TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pItemTime);
450 
451     return MK_E_UNAVAILABLE;
452 }
453 
454 /******************************************************************************
455  *        ClassMoniker_Inverse
456  ******************************************************************************/
457 static HRESULT WINAPI ClassMoniker_Inverse(IMoniker* iface,IMoniker** ppmk)
458 {
459     TRACE("(%p)\n",ppmk);
460 
461     if (!ppmk)
462         return E_POINTER;
463 
464     return CreateAntiMoniker(ppmk);
465 }
466 
467 /******************************************************************************
468  *        ClassMoniker_CommonPrefixWith
469  ******************************************************************************/
470 static HRESULT WINAPI ClassMoniker_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
471 {
472     DWORD mkSys;
473 
474     TRACE("(%p, %p)\n", pmkOther, ppmkPrefix);
475 
476     *ppmkPrefix = NULL;
477 
478     IMoniker_IsSystemMoniker(pmkOther, &mkSys);
479 
480     /* If the other moniker is an class moniker that is equal to this moniker, this method sets *ppmkPrefix */
481     /* to this moniker and returns MK_S_US */
482 
483     if (mkSys == MKSYS_CLASSMONIKER)
484     {
485         if (IMoniker_IsEqual(iface, pmkOther) == S_OK)
486         {
487             *ppmkPrefix = iface;
488 
489             IMoniker_AddRef(iface);
490 
491             return MK_S_US;
492         }
493         else
494             return MK_E_NOPREFIX;
495     }
496     else
497         /* otherwise, the method calls the MonikerCommonPrefixWith function. This function correctly handles */
498         /* the case where the other moniker is a generic composite. */
499         return MonikerCommonPrefixWith(iface, pmkOther, ppmkPrefix);
500 }
501 
502 /******************************************************************************
503  *        ClassMoniker_RelativePathTo
504  ******************************************************************************/
505 static HRESULT WINAPI ClassMoniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
506 {
507     TRACE("(%p, %p)\n",pmOther,ppmkRelPath);
508 
509     if (!ppmkRelPath)
510         return E_POINTER;
511 
512     *ppmkRelPath = NULL;
513 
514     return MK_E_NOTBINDABLE;
515 }
516 
517 /******************************************************************************
518  *        ClassMoniker_GetDisplayName
519  ******************************************************************************/
520 static HRESULT WINAPI ClassMoniker_GetDisplayName(IMoniker* iface,
521                                               IBindCtx* pbc,
522                                               IMoniker* pmkToLeft,
523                                               LPOLESTR *ppszDisplayName)
524 {
525     ClassMoniker *This = impl_from_IMoniker(iface);
526     static const WCHAR wszClsidPrefix[] = {'c','l','s','i','d',':',0};
527 
528     TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, ppszDisplayName);
529 
530     if (!ppszDisplayName)
531         return E_POINTER;
532 
533     if (pmkToLeft)
534         return E_INVALIDARG;
535 
536     *ppszDisplayName = CoTaskMemAlloc(sizeof(wszClsidPrefix) + (CHARS_IN_GUID-2) * sizeof(WCHAR));
537 
538     StringFromGUID2(&This->clsid, *ppszDisplayName+ARRAY_SIZE(wszClsidPrefix)-2, CHARS_IN_GUID);
539 
540     /* note: this overwrites the opening curly bracket of the CLSID string generated above */
541     memcpy(*ppszDisplayName, wszClsidPrefix, sizeof(wszClsidPrefix)-sizeof(WCHAR));
542 
543     /* note: this overwrites the closing curly bracket of the CLSID string generated above */
544     (*ppszDisplayName)[ARRAY_SIZE(wszClsidPrefix)-2+CHARS_IN_GUID-2] = ':';
545     (*ppszDisplayName)[ARRAY_SIZE(wszClsidPrefix)-2+CHARS_IN_GUID-1] = '\0';
546 
547     TRACE("string is %s\n", debugstr_w(*ppszDisplayName));
548     return S_OK;
549 }
550 
551 /******************************************************************************
552  *        ClassMoniker_ParseDisplayName
553  ******************************************************************************/
554 static HRESULT WINAPI ClassMoniker_ParseDisplayName(IMoniker* iface,
555                                                 IBindCtx* pbc,
556                                                 IMoniker* pmkToLeft,
557                                                 LPOLESTR pszDisplayName,
558                                                 ULONG* pchEaten,
559                                                 IMoniker** ppmkOut)
560 {
561     FIXME("(%p, %p, %s, %p, %p)\n", pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
562     return E_NOTIMPL;
563 }
564 
565 /******************************************************************************
566  *        ClassMoniker_IsSystemMoniker
567  ******************************************************************************/
568 static HRESULT WINAPI ClassMoniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
569 {
570     TRACE("(%p,%p)\n",iface,pwdMksys);
571 
572     if (!pwdMksys)
573         return E_POINTER;
574 
575     *pwdMksys = MKSYS_CLASSMONIKER;
576 
577     return S_OK;
578 }
579 
580 /*******************************************************************************
581  *        ClassMonikerIROTData_QueryInterface
582  *******************************************************************************/
583 static HRESULT WINAPI ClassMonikerROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
584 {
585 
586     ClassMoniker *This = impl_from_IROTData(iface);
587 
588     TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppvObject);
589 
590     return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
591 }
592 
593 /***********************************************************************
594  *        ClassMonikerIROTData_AddRef
595  */
596 static ULONG WINAPI ClassMonikerROTData_AddRef(IROTData *iface)
597 {
598     ClassMoniker *This = impl_from_IROTData(iface);
599 
600     TRACE("(%p)\n",iface);
601 
602     return IMoniker_AddRef(&This->IMoniker_iface);
603 }
604 
605 /***********************************************************************
606  *        ClassMonikerIROTData_Release
607  */
608 static ULONG WINAPI ClassMonikerROTData_Release(IROTData* iface)
609 {
610     ClassMoniker *This = impl_from_IROTData(iface);
611 
612     TRACE("(%p)\n",iface);
613 
614     return IMoniker_Release(&This->IMoniker_iface);
615 }
616 
617 /******************************************************************************
618  *        ClassMonikerIROTData_GetComparisonData
619  ******************************************************************************/
620 static HRESULT WINAPI ClassMonikerROTData_GetComparisonData(IROTData* iface,
621                                                          BYTE* pbData,
622                                                          ULONG cbMax,
623                                                          ULONG* pcbData)
624 {
625     ClassMoniker *This = impl_from_IROTData(iface);
626 
627     TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
628 
629     *pcbData = 2*sizeof(CLSID);
630     if (cbMax < *pcbData)
631         return E_OUTOFMEMORY;
632 
633     /* write CLSID of the moniker */
634     memcpy(pbData, &CLSID_ClassMoniker, sizeof(CLSID));
635     /* write CLSID the moniker represents */
636     memcpy(pbData+sizeof(CLSID), &This->clsid, sizeof(CLSID));
637 
638     return S_OK;
639 }
640 
641 /********************************************************************************/
642 /* Virtual function table for the ClassMoniker class which  include IPersist,*/
643 /* IPersistStream and IMoniker functions.                                       */
644 static const IMonikerVtbl ClassMonikerVtbl =
645 {
646     ClassMoniker_QueryInterface,
647     ClassMoniker_AddRef,
648     ClassMoniker_Release,
649     ClassMoniker_GetClassID,
650     ClassMoniker_IsDirty,
651     ClassMoniker_Load,
652     ClassMoniker_Save,
653     ClassMoniker_GetSizeMax,
654     ClassMoniker_BindToObject,
655     ClassMoniker_BindToStorage,
656     ClassMoniker_Reduce,
657     ClassMoniker_ComposeWith,
658     ClassMoniker_Enum,
659     ClassMoniker_IsEqual,
660     ClassMoniker_Hash,
661     ClassMoniker_IsRunning,
662     ClassMoniker_GetTimeOfLastChange,
663     ClassMoniker_Inverse,
664     ClassMoniker_CommonPrefixWith,
665     ClassMoniker_RelativePathTo,
666     ClassMoniker_GetDisplayName,
667     ClassMoniker_ParseDisplayName,
668     ClassMoniker_IsSystemMoniker
669 };
670 
671 /********************************************************************************/
672 /* Virtual function table for the IROTData class.                               */
673 static const IROTDataVtbl ROTDataVtbl =
674 {
675     ClassMonikerROTData_QueryInterface,
676     ClassMonikerROTData_AddRef,
677     ClassMonikerROTData_Release,
678     ClassMonikerROTData_GetComparisonData
679 };
680 
681 /******************************************************************************
682  *         ClassMoniker_Construct (local function)
683  *******************************************************************************/
684 static HRESULT ClassMoniker_Construct(ClassMoniker* This, REFCLSID rclsid)
685 {
686     TRACE("(%p,%s)\n",This,debugstr_guid(rclsid));
687 
688     /* Initialize the virtual function table. */
689     This->IMoniker_iface.lpVtbl = &ClassMonikerVtbl;
690     This->IROTData_iface.lpVtbl = &ROTDataVtbl;
691     This->ref           = 0;
692     This->clsid         = *rclsid;
693     This->pMarshal      = NULL;
694 
695     return S_OK;
696 }
697 
698 /******************************************************************************
699  *        CreateClassMoniker	[OLE32.@]
700  ******************************************************************************/
701 HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker **ppmk)
702 {
703     ClassMoniker* newClassMoniker;
704     HRESULT       hr;
705 
706     TRACE("(%s,%p)\n", debugstr_guid(rclsid), ppmk);
707 
708     newClassMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ClassMoniker));
709 
710     if (!newClassMoniker)
711         return STG_E_INSUFFICIENTMEMORY;
712 
713     hr = ClassMoniker_Construct(newClassMoniker, rclsid);
714 
715     if (FAILED(hr))
716     {
717         HeapFree(GetProcessHeap(), 0, newClassMoniker);
718         return hr;
719     }
720 
721     return ClassMoniker_QueryInterface(&newClassMoniker->IMoniker_iface, &IID_IMoniker,
722                                        (void**)ppmk);
723 }
724 
725 HRESULT ClassMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName, LPDWORD pchEaten,
726                                            IMoniker **ppmk)
727 {
728     HRESULT hr;
729     LPCWSTR s = wcschr(szDisplayName, ':');
730     LPCWSTR end;
731     CLSID clsid;
732     BYTE table[256];
733     int i;
734 
735     if (!s)
736         return MK_E_SYNTAX;
737 
738     s++;
739 
740     for (end = s; *end && (*end != ':'); end++)
741         ;
742 
743     TRACE("parsing %s\n", debugstr_wn(s, end - s));
744 
745     /* validate the CLSID string */
746     if (s[0] == '{')
747     {
748         if ((end - s != 38) || (s[37] != '}'))
749             return MK_E_SYNTAX;
750         s++;
751     }
752     else
753     {
754         if (end - s != 36)
755             return MK_E_SYNTAX;
756     }
757 
758     for (i=0; i<36; i++)
759     {
760         if ((i == 8)||(i == 13)||(i == 18)||(i == 23))
761         {
762             if (s[i] != '-')
763                 return MK_E_SYNTAX;
764             continue;
765         }
766         if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
767               ((s[i] >= 'a') && (s[i] <= 'f'))  ||
768               ((s[i] >= 'A') && (s[i] <= 'F'))))
769             return MK_E_SYNTAX;
770     }
771 
772     /* quick lookup table */
773     memset(table, 0, 256);
774 
775     for (i = 0; i < 10; i++)
776         table['0' + i] = i;
777     for (i = 0; i < 6; i++)
778     {
779         table['A' + i] = i+10;
780         table['a' + i] = i+10;
781     }
782 
783     /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */
784 
785     clsid.Data1 = (table[s[0]] << 28 | table[s[1]] << 24 | table[s[2]] << 20 | table[s[3]] << 16 |
786                    table[s[4]] << 12 | table[s[5]] << 8  | table[s[6]] << 4  | table[s[7]]);
787     clsid.Data2 = table[s[9]] << 12  | table[s[10]] << 8 | table[s[11]] << 4 | table[s[12]];
788     clsid.Data3 = table[s[14]] << 12 | table[s[15]] << 8 | table[s[16]] << 4 | table[s[17]];
789 
790     /* these are just sequential bytes */
791     clsid.Data4[0] = table[s[19]] << 4 | table[s[20]];
792     clsid.Data4[1] = table[s[21]] << 4 | table[s[22]];
793     clsid.Data4[2] = table[s[24]] << 4 | table[s[25]];
794     clsid.Data4[3] = table[s[26]] << 4 | table[s[27]];
795     clsid.Data4[4] = table[s[28]] << 4 | table[s[29]];
796     clsid.Data4[5] = table[s[30]] << 4 | table[s[31]];
797     clsid.Data4[6] = table[s[32]] << 4 | table[s[33]];
798     clsid.Data4[7] = table[s[34]] << 4 | table[s[35]];
799 
800     hr = CreateClassMoniker(&clsid, ppmk);
801     if (SUCCEEDED(hr))
802         *pchEaten = (*end == ':' ? end + 1 : end) - szDisplayName;
803     return hr;
804 }
805 
806 HRESULT WINAPI ClassMoniker_CreateInstance(IClassFactory *iface,
807     IUnknown *pUnk, REFIID riid, void **ppv)
808 {
809     HRESULT hr;
810     IMoniker *pmk;
811 
812     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
813 
814     *ppv = NULL;
815 
816     if (pUnk)
817         return CLASS_E_NOAGGREGATION;
818 
819     hr = CreateClassMoniker(&CLSID_NULL, &pmk);
820     if (FAILED(hr)) return hr;
821 
822     hr = IMoniker_QueryInterface(pmk, riid, ppv);
823     IMoniker_Release(pmk);
824 
825     return hr;
826 }
827