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