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