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