Reactos
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
36WINE_DEFAULT_DEBUG_CHANNEL(ole);
37
38#define CHARS_IN_GUID 39
39
40/* ClassMoniker data structure */
41typedef 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
50static inline ClassMoniker *impl_from_IMoniker(IMoniker *iface)
51{
52 return CONTAINING_RECORD(iface, ClassMoniker, IMoniker_iface);
53}
54
55static inline ClassMoniker *impl_from_IROTData(IROTData *iface)
56{
57 return CONTAINING_RECORD(iface, ClassMoniker, IROTData_iface);
58}
59
60/*******************************************************************************
61 * ClassMoniker_QueryInterface
62 *******************************************************************************/
63static 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 ******************************************************************************/
109static 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 ******************************************************************************/
121static 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 ******************************************************************************/
143static 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 ******************************************************************************/
158static 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 ******************************************************************************/
172static 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 ******************************************************************************/
192static 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 ******************************************************************************/
209static 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 ******************************************************************************/
222static 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 ******************************************************************************/
260static 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 ******************************************************************************/
273static 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 ******************************************************************************/
293static 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 ******************************************************************************/
368static 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 ******************************************************************************/
383static 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 ******************************************************************************/
416static 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 ******************************************************************************/
430static 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 ******************************************************************************/
444static 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 ******************************************************************************/
457static 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 ******************************************************************************/
470static 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 ******************************************************************************/
505static 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 ******************************************************************************/
520static 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 ******************************************************************************/
554static 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 ******************************************************************************/
568static 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 *******************************************************************************/
583static 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 */
596static 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 */
608static 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 ******************************************************************************/
620static 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. */
644static 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. */
673static 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 *******************************************************************************/
684static 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 ******************************************************************************/
701HRESULT 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
725HRESULT 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
806HRESULT 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}