ntdll: Implement KeyNameInformation.
[wine] / dlls / ole32 / filemoniker.c
1 /*
2  * FileMonikers implementation
3  *
4  * Copyright 1999  Noomen Hamza
5  * Copyright 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 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winnls.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36 #include "objbase.h"
37 #include "moniker.h"
38
39 #include "compobj_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42
43 /* filemoniker data structure */
44 typedef struct FileMonikerImpl{
45
46     const IMonikerVtbl*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/
47
48     /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether
49      * two monikers are equal. That's whay IROTData interface is implemented by monikers.
50      */
51     const IROTDataVtbl*  lpvtbl2;  /* VTable relative to the IROTData interface.*/
52
53     LONG ref; /* reference counter for this object */
54
55     LPOLESTR filePathName; /* path string identified by this filemoniker */
56
57     IUnknown *pMarshal; /* custom marshaler */
58 } FileMonikerImpl;
59
60 static inline IMoniker *impl_from_IROTData( IROTData *iface )
61 {
62     return (IMoniker *)((char*)iface - FIELD_OFFSET(FileMonikerImpl, lpvtbl2));
63 }
64
65 /* Local function used by filemoniker implementation */
66 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
67 static HRESULT FileMonikerImpl_Destroy(FileMonikerImpl* iface);
68
69 /*******************************************************************************
70  *        FileMoniker_QueryInterface
71  */
72 static HRESULT WINAPI
73 FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
74 {
75     FileMonikerImpl *This = (FileMonikerImpl *)iface;
76
77     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
78
79     /* Perform a sanity check on the parameters.*/
80     if ( (This==0) || (ppvObject==0) )
81         return E_INVALIDARG;
82
83     /* Initialize the return parameter */
84     *ppvObject = 0;
85
86     /* Compare the riid with the interface IDs implemented by this object.*/
87     if (IsEqualIID(&IID_IUnknown, riid)      ||
88         IsEqualIID(&IID_IPersist, riid)      ||
89         IsEqualIID(&IID_IPersistStream,riid) ||
90         IsEqualIID(&IID_IMoniker, riid)
91        )
92         *ppvObject = iface;
93
94     else if (IsEqualIID(&IID_IROTData, riid))
95         *ppvObject = &This->lpvtbl2;
96     else if (IsEqualIID(&IID_IMarshal, riid))
97     {
98         HRESULT hr = S_OK;
99         if (!This->pMarshal)
100             hr = MonikerMarshal_Create(iface, &This->pMarshal);
101         if (hr != S_OK)
102             return hr;
103         return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
104     }
105
106     /* Check that we obtained an interface.*/
107     if ((*ppvObject)==0)
108         return E_NOINTERFACE;
109
110     /* Query Interface always increases the reference count by one when it is successful */
111     IMoniker_AddRef(iface);
112
113     return S_OK;
114 }
115
116 /******************************************************************************
117  *        FileMoniker_AddRef
118  */
119 static ULONG WINAPI
120 FileMonikerImpl_AddRef(IMoniker* iface)
121 {
122     FileMonikerImpl *This = (FileMonikerImpl *)iface;
123
124     TRACE("(%p)\n",iface);
125
126     return InterlockedIncrement(&This->ref);
127 }
128
129 /******************************************************************************
130  *        FileMoniker_Release
131  */
132 static ULONG WINAPI
133 FileMonikerImpl_Release(IMoniker* iface)
134 {
135     FileMonikerImpl *This = (FileMonikerImpl *)iface;
136     ULONG ref;
137
138     TRACE("(%p)\n",iface);
139
140     ref = InterlockedDecrement(&This->ref);
141
142     /* destroy the object if there's no more reference on it */
143     if (ref == 0) FileMonikerImpl_Destroy(This);
144
145     return ref;
146 }
147
148 /******************************************************************************
149  *        FileMoniker_GetClassID
150  */
151 static HRESULT WINAPI
152 FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID)
153 {
154     TRACE("(%p,%p)\n",iface,pClassID);
155
156     if (pClassID==NULL)
157         return E_POINTER;
158
159     *pClassID = CLSID_FileMoniker;
160
161     return S_OK;
162 }
163
164 /******************************************************************************
165  *        FileMoniker_IsDirty
166  *
167  * Note that the OLE-provided implementations of the IPersistStream::IsDirty
168  * method in the OLE-provided moniker interfaces always return S_FALSE because
169  * their internal state never changes.
170  */
171 static HRESULT WINAPI
172 FileMonikerImpl_IsDirty(IMoniker* iface)
173 {
174
175     TRACE("(%p)\n",iface);
176
177     return S_FALSE;
178 }
179
180 /******************************************************************************
181  *        FileMoniker_Load
182  *
183  * this function locates and reads from the stream the filePath string
184  * written by FileMonikerImpl_Save
185  */
186 static HRESULT WINAPI
187 FileMonikerImpl_Load(IMoniker* iface, IStream* pStm)
188 {
189     HRESULT res;
190     CHAR* filePathA = NULL;
191     WCHAR* filePathW = NULL;
192     ULONG bread;
193     WORD  wbuffer;
194     DWORD dwbuffer, bytesA, bytesW, len;
195     int i;
196
197     FileMonikerImpl *This = (FileMonikerImpl *)iface;
198
199     TRACE("(%p,%p)\n",iface,pStm);
200
201     /* first WORD */
202     res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
203     if (bread!=sizeof(WORD))
204     {
205         WARN("Couldn't read 0 word\n");
206         goto fail;
207     }
208
209     /* read filePath string length (plus one) */
210     res=IStream_Read(pStm,&bytesA,sizeof(DWORD),&bread);
211     if (bread != sizeof(DWORD))
212     {
213         WARN("Couldn't read file string length\n");
214         goto fail;
215     }
216
217     /* read filePath string */
218     filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
219     if (!filePathA)
220     {
221         res = E_OUTOFMEMORY;
222         goto fail;
223     }
224
225     res=IStream_Read(pStm,filePathA,bytesA,&bread);
226     if (bread != bytesA)
227     {
228         WARN("Couldn't read file path string\n");
229         goto fail;
230     }
231
232     /* read the unknown value */
233     IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
234     if (bread != sizeof(WORD))
235     {
236         WARN("Couldn't read unknown value\n");
237         goto fail;
238     }
239
240     /* read the DEAD constant */
241     IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
242     if (bread != sizeof(WORD))
243     {
244         WARN("Couldn't read DEAD constant\n");
245         goto fail;
246     }
247
248     for(i=0;i<5;i++)
249     {
250         res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
251         if (bread!=sizeof(DWORD))
252         {
253             WARN("Couldn't read 0 padding\n");
254             goto fail;
255         }
256     }
257
258     res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
259     if (bread!=sizeof(DWORD))
260         goto fail;
261
262     if (!dwbuffer) /* No W-string */
263     {        
264         bytesA--;
265         len=MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, bytesA, NULL, 0);
266         if (!len)
267             goto fail;
268
269         filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
270         if (!filePathW)
271         {
272             res = E_OUTOFMEMORY;
273             goto fail;
274         }
275         MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, -1, filePathW, len+1);
276         goto succeed;
277     }
278
279     if (dwbuffer < 6)
280         goto fail;
281
282     bytesW=dwbuffer - 6;
283
284     res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
285     if (bread!=sizeof(DWORD) || dwbuffer!=bytesW)
286         goto fail;
287
288     res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
289     if (bread!=sizeof(WORD) || wbuffer!=0x3)
290         goto fail;
291
292     len=bytesW/sizeof(WCHAR);
293     filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
294     if(!filePathW)
295     {
296          res = E_OUTOFMEMORY;
297          goto fail;
298     }
299     res=IStream_Read(pStm,filePathW,bytesW,&bread);
300     if (bread!=bytesW)
301          goto fail;
302
303     filePathW[len]=0;
304
305  succeed:
306     HeapFree(GetProcessHeap(),0,filePathA);
307     HeapFree(GetProcessHeap(),0,This->filePathName);
308     This->filePathName=filePathW;
309
310     return S_OK;
311
312  fail:
313     HeapFree(GetProcessHeap(), 0, filePathA);
314     HeapFree(GetProcessHeap(), 0, filePathW);
315
316     if (SUCCEEDED(res))
317          res = E_FAIL;
318     return res;
319 }
320
321 /******************************************************************************
322  *        FileMoniker_Save
323  *
324  * This function saves data of this object. In the beginning I thought
325  * that I have just to write the filePath string on Stream. But, when I
326  * tested this function with windows program samples, I noticed that it
327  * was not the case. This implementation is based on XP SP2. Other versions
328  * of Windows have minor variations.
329  *
330  * Data which must be written on stream is:
331  * 1) WORD constant: zero (not validated by Windows)
332  * 2) length of the path string ("\0" included)
333  * 3) path string type A
334  * 4) Unknown WORD value: Frequently 0xFFFF, but not always. If set very large,
335  *     Windows returns E_OUTOFMEMORY
336  * 5) WORD Constant: 0xDEAD (not validated by Windows)
337  * 6) five DWORD constant: zero (not validated by Windows)
338  * 7) If we're only writing the multibyte version,
339  *     write a zero DWORD and finish.
340  *
341  * 8) DWORD: double-length of the path string type W ("\0" not
342  *    included)
343  * 9) WORD constant: 0x3
344  * 10) filePath unicode string.
345  *
346  */
347 static HRESULT WINAPI
348 FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
349 {
350     FileMonikerImpl *This = (FileMonikerImpl *)iface;
351
352     HRESULT res;
353     LPOLESTR filePathW=This->filePathName;
354     CHAR*    filePathA;
355     DWORD bytesA, bytesW, len;
356
357     static const WORD FFFF = 0xFFFF; /* Constants */
358     static const WORD DEAD = 0xDEAD;
359     static const DWORD ZERO     = 0;
360     static const WORD  THREE    = 0x3;
361
362     int i;
363     BOOL bUsedDefault, bWriteWide;
364
365     TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
366
367     if (pStm==NULL)
368         return E_POINTER;
369
370     /* write a 0 WORD */
371     res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
372     if (FAILED(res)) return res;
373
374     /* write length of filePath string ( 0 included )*/
375     bytesA = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
376     res=IStream_Write(pStm,&bytesA,sizeof(DWORD),NULL);
377     if (FAILED(res)) return res;
378
379     /* write A string (with '\0') */
380     filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
381     if (!filePathA)
382         return E_OUTOFMEMORY;
383     WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, bytesA, NULL, &bUsedDefault);
384     res=IStream_Write(pStm,filePathA,bytesA,NULL);
385     HeapFree(GetProcessHeap(),0,filePathA);
386     if (FAILED(res)) return res;
387
388     /* write a WORD 0xFFFF */
389     res=IStream_Write(pStm,&FFFF,sizeof(WORD),NULL);
390     if (FAILED(res)) return res;
391
392     /* write a WORD 0xDEAD */
393     res=IStream_Write(pStm,&DEAD,sizeof(WORD),NULL);
394     if (FAILED(res)) return res;
395
396     /* write 5 zero DWORDs */
397     for(i=0;i<5;i++)
398     {
399         res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
400         if (FAILED(res)) return res;
401     }
402
403     /* Write the wide version if:
404      *    + couldn't convert to CP_ACP, 
405      * or + it's a directory, 
406      * or + there's a character > 0xFF 
407      */
408     len = lstrlenW(filePathW);
409     bWriteWide = (bUsedDefault || (len > 0 && filePathW[len-1]=='\\' ));
410     if (!bWriteWide)
411     {
412         WCHAR* pch;
413         for(pch=filePathW;*pch;++pch) 
414         {
415             if (*pch > 0xFF)
416             {
417                 bWriteWide = TRUE;
418                 break;
419             }
420         }
421     }
422
423     if (!bWriteWide)
424     {
425         res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
426         return res;
427     }
428
429     /* write bytes needed for the filepathW (without 0) + 6 */
430     bytesW = len*sizeof(WCHAR) + 6;
431     res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
432     if (FAILED(res)) return res;
433
434     /* try again, without the extra 6 */
435     bytesW -= 6;
436     res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
437     if (FAILED(res)) return res;
438
439     /* write a WORD 3 */
440     res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
441     if (FAILED(res)) return res;
442
443     /* write W string (no 0) */
444     res=IStream_Write(pStm,filePathW,bytesW,NULL);
445
446     return res;
447 }
448
449 /******************************************************************************
450  *        FileMoniker_GetSizeMax
451  */
452 static HRESULT WINAPI
453 FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
454 {
455     FileMonikerImpl *This = (FileMonikerImpl *)iface;
456
457     TRACE("(%p,%p)\n",iface,pcbSize);
458
459     if (!pcbSize)
460         return E_POINTER;
461
462     /* We could calculate exactly (see ...::Save()) but instead
463      * we'll make a quick over-estimate, like Windows (NT4, XP) does.
464      */
465     pcbSize->u.LowPart  = 0x38 + 4 * lstrlenW(This->filePathName);
466     pcbSize->u.HighPart = 0;
467
468     return S_OK;
469 }
470
471 /******************************************************************************
472  *        FileMoniker_Destroy (local function)
473  *******************************************************************************/
474 HRESULT FileMonikerImpl_Destroy(FileMonikerImpl* This)
475 {
476     TRACE("(%p)\n",This);
477
478     if (This->pMarshal) IUnknown_Release(This->pMarshal);
479     HeapFree(GetProcessHeap(),0,This->filePathName);
480     HeapFree(GetProcessHeap(),0,This);
481
482     return S_OK;
483 }
484
485 /******************************************************************************
486  *                  FileMoniker_BindToObject
487  */
488 static HRESULT WINAPI
489 FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
490                              REFIID riid, VOID** ppvResult)
491 {
492     HRESULT   res=E_FAIL;
493     CLSID     clsID;
494     IUnknown* pObj=0;
495     IRunningObjectTable *prot=0;
496     IPersistFile  *ppf=0;
497     IClassFactory *pcf=0;
498     IClassActivator *pca=0;
499
500     FileMonikerImpl *This = (FileMonikerImpl *)iface;
501
502     *ppvResult=0;
503
504     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
505
506     if(pmkToLeft==NULL){
507
508         res=IBindCtx_GetRunningObjectTable(pbc,&prot);
509
510         if (SUCCEEDED(res)){
511             /* if the requested class was loaded before ! we don't need to reload it */
512             res = IRunningObjectTable_GetObject(prot,iface,&pObj);
513
514             if (res==S_FALSE){
515                 /* first activation of this class */
516                 res=GetClassFile(This->filePathName,&clsID);
517                 if (SUCCEEDED(res)){
518
519                     res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IPersistFile,(void**)&ppf);
520                     if (SUCCEEDED(res)){
521
522                         res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
523                         if (SUCCEEDED(res)){
524
525                             pObj=(IUnknown*)ppf;
526                             IUnknown_AddRef(pObj);
527                         }
528                     }
529                 }
530             }
531         }
532     }
533     else{
534         res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf);
535
536         if (res==E_NOINTERFACE){
537
538             res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
539
540             if (res==E_NOINTERFACE)
541                 return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
542         }
543         if (pcf!=NULL){
544
545             IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)&ppf);
546
547             res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
548
549             if (SUCCEEDED(res)){
550
551                 pObj=(IUnknown*)ppf;
552                 IUnknown_AddRef(pObj);
553             }
554         }
555         if (pca!=NULL){
556
557             FIXME("()\n");
558
559             /*res=GetClassFile(This->filePathName,&clsID);
560
561             if (SUCCEEDED(res)){
562
563                 res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf);
564
565                 if (SUCCEEDED(res)){
566
567                     pObj=(IUnknown*)ppf;
568                     IUnknown_AddRef(pObj);
569                 }
570             }*/
571         }
572     }
573
574     if (pObj!=NULL){
575         /* get the requested interface from the loaded class */
576         res= IUnknown_QueryInterface(pObj,riid,ppvResult);
577
578         IBindCtx_RegisterObjectBound(pbc,*ppvResult);
579
580         IUnknown_Release(pObj);
581     }
582
583     if (prot!=NULL)
584         IRunningObjectTable_Release(prot);
585
586     if (ppf!=NULL)
587         IPersistFile_Release(ppf);
588
589     if (pca!=NULL)
590         IClassActivator_Release(pca);
591
592     if (pcf!=NULL)
593         IClassFactory_Release(pcf);
594
595     return res;
596 }
597
598 /******************************************************************************
599  *        FileMoniker_BindToStorage
600  */
601 static HRESULT WINAPI
602 FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
603                               REFIID riid, VOID** ppvObject)
604 {
605     LPOLESTR filePath=0;
606     IStorage *pstg=0;
607     HRESULT res;
608
609     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
610
611     if (pmkToLeft==NULL){
612
613         if (IsEqualIID(&IID_IStorage, riid)){
614
615             /* get the file name */
616             IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath);
617
618             /* verify if the file contains a storage object */
619             res=StgIsStorageFile(filePath);
620
621             if(res==S_OK){
622
623                 res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
624
625                 if (SUCCEEDED(res)){
626
627                     *ppvObject=pstg;
628
629                     IStorage_AddRef(pstg);
630
631                     return res;
632                 }
633             }
634             CoTaskMemFree(filePath);
635         }
636         else
637             if ( (IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)) )
638                 return E_FAIL;
639             else
640                 return E_NOINTERFACE;
641     }
642     else {
643
644         FIXME("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
645
646         return E_NOTIMPL;
647     }
648     return res;
649 }
650
651 /******************************************************************************
652  *        FileMoniker_Reduce
653  ******************************************************************************/
654 static HRESULT WINAPI
655 FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
656                        IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
657 {
658     TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
659
660     if (ppmkReduced==NULL)
661         return E_POINTER;
662
663     IMoniker_AddRef(iface);
664
665     *ppmkReduced=iface;
666
667     return MK_S_REDUCED_TO_SELF;
668 }
669
670 /******************************************************************************
671  *        FileMoniker_ComposeWith
672  */
673 static HRESULT WINAPI
674 FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
675                             BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
676 {
677     HRESULT res;
678     LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0;
679     static const WCHAR twoPoint[]={'.','.',0};
680     static const WCHAR bkSlash[]={'\\',0};
681     IBindCtx *bind=0;
682     int i=0,j=0,lastIdx1=0,lastIdx2=0;
683     DWORD mkSys;
684
685     TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
686
687     if (ppmkComposite==NULL)
688         return E_POINTER;
689
690     if (pmkRight==NULL)
691         return E_INVALIDARG;
692
693     *ppmkComposite=0;
694
695     IMoniker_IsSystemMoniker(pmkRight,&mkSys);
696
697     /* check if we have two FileMonikers to compose or not */
698     if(mkSys==MKSYS_FILEMONIKER){
699
700         CreateBindCtx(0,&bind);
701
702         IMoniker_GetDisplayName(iface,bind,NULL,&str1);
703         IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2);
704
705         /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */
706         lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1;
707         lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1;
708
709         if ((lastIdx1==-1 && lastIdx2>-1)||(lastIdx1==1 && lstrcmpW(strDec1[0],twoPoint)==0))
710             return MK_E_SYNTAX;
711
712         if(lstrcmpW(strDec1[lastIdx1],bkSlash)==0)
713             lastIdx1--;
714
715         /* for etch "..\" in the left of str2 remove the right element from str1 */
716         for(i=0; ( (lastIdx1>=0) && (strDec2[i]!=NULL) && (lstrcmpW(strDec2[i],twoPoint)==0) ) ;i+=2){
717
718             lastIdx1-=2;
719         }
720
721         /* the length of the composed path string  is raised by the sum of the two paths lengths  */
722         newStr=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1));
723
724           if (newStr==NULL)
725                 return E_OUTOFMEMORY;
726
727         /* new path is the concatenation of the rest of str1 and str2 */
728         for(*newStr=0,j=0;j<=lastIdx1;j++)
729             strcatW(newStr,strDec1[j]);
730
731         if ((strDec2[i]==NULL && lastIdx1>-1 && lastIdx2>-1) || lstrcmpW(strDec2[i],bkSlash)!=0)
732             strcatW(newStr,bkSlash);
733
734         for(j=i;j<=lastIdx2;j++)
735             strcatW(newStr,strDec2[j]);
736
737         /* create a new moniker with the new string */
738         res=CreateFileMoniker(newStr,ppmkComposite);
739
740         /* free all strings space memory used by this function */
741         HeapFree(GetProcessHeap(),0,newStr);
742
743         for(i=0; strDec1[i]!=NULL;i++)
744             CoTaskMemFree(strDec1[i]);
745         for(i=0; strDec2[i]!=NULL;i++)
746             CoTaskMemFree(strDec2[i]);
747         CoTaskMemFree(strDec1);
748         CoTaskMemFree(strDec2);
749
750         CoTaskMemFree(str1);
751         CoTaskMemFree(str2);
752
753         return res;
754     }
755     else if(mkSys==MKSYS_ANTIMONIKER){
756
757         *ppmkComposite=NULL;
758         return S_OK;
759     }
760     else if (fOnlyIfNotGeneric){
761
762         *ppmkComposite=NULL;
763         return MK_E_NEEDGENERIC;
764     }
765     else
766
767         return CreateGenericComposite(iface,pmkRight,ppmkComposite);
768 }
769
770 /******************************************************************************
771  *        FileMoniker_Enum
772  */
773 static HRESULT WINAPI
774 FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
775 {
776     TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
777
778     if (ppenumMoniker == NULL)
779         return E_POINTER;
780
781     *ppenumMoniker = NULL;
782
783     return S_OK;
784 }
785
786 /******************************************************************************
787  *        FileMoniker_IsEqual
788  */
789 static HRESULT WINAPI
790 FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
791 {
792     FileMonikerImpl *This = (FileMonikerImpl *)iface;
793     CLSID clsid;
794     LPOLESTR filePath;
795     IBindCtx* bind;
796     HRESULT res;
797
798     TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
799
800     if (pmkOtherMoniker==NULL)
801         return S_FALSE;
802
803     IMoniker_GetClassID(pmkOtherMoniker,&clsid);
804
805     if (!IsEqualCLSID(&clsid,&CLSID_FileMoniker))
806         return S_FALSE;
807
808     res = CreateBindCtx(0,&bind);
809     if (FAILED(res)) return res;
810
811     res = S_FALSE;
812     if (SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath))) {
813         if (!lstrcmpiW(filePath, This->filePathName))
814             res = S_OK;
815         CoTaskMemFree(filePath);
816     }
817
818     IBindCtx_Release(bind);
819     return res;
820 }
821
822 /******************************************************************************
823  *        FileMoniker_Hash
824  */
825 static HRESULT WINAPI
826 FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
827 {
828     FileMonikerImpl *This = (FileMonikerImpl *)iface;
829
830     int  h = 0,i,skip,len;
831     int  off = 0;
832     LPOLESTR val;
833
834     if (pdwHash==NULL)
835         return E_POINTER;
836
837     val =  This->filePathName;
838     len = lstrlenW(val);
839
840     if (len < 16) {
841         for (i = len ; i > 0; i--) {
842             h = (h * 37) + val[off++];
843         }
844     } else {
845         /* only sample some characters */
846         skip = len / 8;
847         for (i = len ; i > 0; i -= skip, off += skip) {
848             h = (h * 39) + val[off];
849         }
850     }
851
852     *pdwHash=h;
853
854     return S_OK;
855 }
856
857 /******************************************************************************
858  *        FileMoniker_IsRunning
859  */
860 static HRESULT WINAPI
861 FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
862                           IMoniker* pmkNewlyRunning)
863 {
864     IRunningObjectTable* rot;
865     HRESULT res;
866
867     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
868
869     if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) )
870         return S_OK;
871
872     if (pbc==NULL)
873         return E_POINTER;
874
875     res=IBindCtx_GetRunningObjectTable(pbc,&rot);
876
877     if (FAILED(res))
878         return res;
879
880     res = IRunningObjectTable_IsRunning(rot,iface);
881
882     IRunningObjectTable_Release(rot);
883
884     return res;
885 }
886
887 /******************************************************************************
888  *        FileMoniker_GetTimeOfLastChange
889  ******************************************************************************/
890 static HRESULT WINAPI
891 FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
892                                     IMoniker* pmkToLeft, FILETIME* pFileTime)
893 {
894     FileMonikerImpl *This = (FileMonikerImpl *)iface;
895     IRunningObjectTable* rot;
896     HRESULT res;
897     WIN32_FILE_ATTRIBUTE_DATA info;
898
899     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime);
900
901     if (pFileTime==NULL)
902         return E_POINTER;
903
904     if (pmkToLeft!=NULL)
905         return E_INVALIDARG;
906
907     res=IBindCtx_GetRunningObjectTable(pbc,&rot);
908
909     if (FAILED(res))
910         return res;
911
912     res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime);
913
914     if (FAILED(res)){ /* the moniker is not registered */
915
916         if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info))
917             return MK_E_NOOBJECT;
918
919         *pFileTime=info.ftLastWriteTime;
920     }
921
922     return S_OK;
923 }
924
925 /******************************************************************************
926  *        FileMoniker_Inverse
927  */
928 static HRESULT WINAPI
929 FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
930 {
931     TRACE("(%p,%p)\n",iface,ppmk);
932
933     return CreateAntiMoniker(ppmk);
934 }
935
936 /******************************************************************************
937  *        FileMoniker_CommonPrefixWith
938  */
939 static HRESULT WINAPI
940 FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
941 {
942
943     LPOLESTR pathThis,pathOther,*stringTable1,*stringTable2,commonPath;
944     IBindCtx *pbind;
945     DWORD mkSys;
946     ULONG nb1,nb2,i,sameIdx;
947     BOOL machimeNameCase=FALSE;
948
949     if (ppmkPrefix==NULL)
950         return E_POINTER;
951
952     if (pmkOther==NULL)
953         return E_INVALIDARG;
954
955     *ppmkPrefix=0;
956
957     /* check if we have the same type of moniker */
958     IMoniker_IsSystemMoniker(pmkOther,&mkSys);
959
960     if(mkSys==MKSYS_FILEMONIKER){
961         HRESULT ret;
962
963         CreateBindCtx(0,&pbind);
964
965         /* create a string based on common part of the two paths */
966
967         IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis);
968         IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther);
969
970         nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1);
971         nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2);
972
973         if (nb1==0 || nb2==0)
974             return MK_E_NOPREFIX;
975
976         commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1));
977
978         *commonPath=0;
979
980         for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) &&
981                          (stringTable2[sameIdx]!=NULL) &&
982                          (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++);
983
984         if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){
985
986             machimeNameCase=TRUE;
987
988             for(i=2;i<sameIdx;i++)
989
990                 if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){
991                     machimeNameCase=FALSE;
992                     break;
993             }
994         }
995
996         if (machimeNameCase && *stringTable1[sameIdx-1]=='\\')
997             sameIdx--;
998
999         if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
1000             ret = MK_E_NOPREFIX;
1001         else
1002         {
1003             for(i=0;i<sameIdx;i++)
1004                 strcatW(commonPath,stringTable1[i]);
1005     
1006             for(i=0;i<nb1;i++)
1007                 CoTaskMemFree(stringTable1[i]);
1008     
1009             CoTaskMemFree(stringTable1);
1010     
1011             for(i=0;i<nb2;i++)
1012                 CoTaskMemFree(stringTable2[i]);
1013     
1014             CoTaskMemFree(stringTable2);
1015     
1016             ret = CreateFileMoniker(commonPath,ppmkPrefix);
1017         }
1018         HeapFree(GetProcessHeap(),0,commonPath);
1019         return ret;
1020     }
1021     else
1022         return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
1023 }
1024
1025 /******************************************************************************
1026  *        DecomposePath (local function)
1027  */
1028 int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable)
1029 {
1030     static const WCHAR bSlash[] = {'\\',0};
1031     LPOLESTR word;
1032     int i=0,j,tabIndex=0, ret=0;
1033     LPOLESTR *strgtable ;
1034
1035     int len=lstrlenW(str);
1036
1037     TRACE("%s, %p\n", debugstr_w(str), *stringTable);
1038
1039     strgtable = CoTaskMemAlloc(len*sizeof(WCHAR));
1040
1041     if (strgtable==NULL)
1042         return E_OUTOFMEMORY;
1043
1044     word = CoTaskMemAlloc((len + 1)*sizeof(WCHAR));
1045
1046     if (word==NULL)
1047     {
1048         ret = E_OUTOFMEMORY;
1049         goto lend;
1050     }
1051
1052     while(str[i]!=0){
1053
1054         if(str[i]==bSlash[0]){
1055
1056             strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR));
1057
1058             if (strgtable[tabIndex]==NULL)
1059             {
1060                 ret = E_OUTOFMEMORY;
1061                 goto lend;
1062             }
1063
1064             strcpyW(strgtable[tabIndex++],bSlash);
1065
1066             i++;
1067
1068         }
1069         else {
1070
1071             for(j=0; str[i]!=0 && str[i]!=bSlash[0] ; i++,j++)
1072                 word[j]=str[i];
1073
1074             word[j]=0;
1075
1076             strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1));
1077
1078             if (strgtable[tabIndex]==NULL)
1079             {
1080                 ret = E_OUTOFMEMORY;
1081                 goto lend;
1082             }
1083
1084             strcpyW(strgtable[tabIndex++],word);
1085         }
1086     }
1087     strgtable[tabIndex]=NULL;
1088
1089     *stringTable=strgtable;
1090
1091     ret = tabIndex;
1092
1093 lend:
1094     if (ret < 0)
1095     {
1096         for (i = 0; i < tabIndex; i++)
1097             CoTaskMemFree(strgtable[i]);
1098
1099         CoTaskMemFree(strgtable);
1100     }
1101
1102     if (word)
1103         CoTaskMemFree(word);
1104
1105     return ret;
1106 }
1107
1108 /******************************************************************************
1109  *        FileMoniker_RelativePathTo
1110  */
1111 static HRESULT WINAPI
1112 FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
1113 {
1114     IBindCtx *bind;
1115     HRESULT res;
1116     LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
1117     DWORD len1=0,len2=0,sameIdx=0,j=0;
1118     static const WCHAR back[] ={'.','.','\\',0};
1119
1120     TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
1121
1122     if (ppmkRelPath==NULL)
1123         return E_POINTER;
1124
1125     if (pmOther==NULL)
1126         return E_INVALIDARG;
1127
1128     res=CreateBindCtx(0,&bind);
1129     if (FAILED(res))
1130         return res;
1131
1132     res=IMoniker_GetDisplayName(iface,bind,NULL,&str1);
1133     if (FAILED(res))
1134         return res;
1135     res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2);
1136     if (FAILED(res))
1137         return res;
1138
1139     len1=FileMonikerImpl_DecomposePath(str1,&tabStr1);
1140     len2=FileMonikerImpl_DecomposePath(str2,&tabStr2);
1141
1142     if (FAILED(len1) || FAILED(len2))
1143         return E_OUTOFMEMORY;
1144
1145     /* count the number of similar items from the begin of the two paths */
1146     for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) &&
1147                    (tabStr2[sameIdx]!=NULL) &&
1148                (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++);
1149
1150     /* begin the construction of relativePath */
1151     /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */
1152     /* by "..\\" in the begin */
1153     relPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2)));
1154
1155     *relPath=0;
1156
1157     if (len2>0 && !(len1==1 && len2==1 && sameIdx==0))
1158         for(j=sameIdx;(tabStr1[j] != NULL); j++)
1159             if (*tabStr1[j]!='\\')
1160                 strcatW(relPath,back);
1161
1162     /* add items of the second path (similar items with the first path are not included) to the relativePath */
1163     for(j=sameIdx;tabStr2[j]!=NULL;j++)
1164         strcatW(relPath,tabStr2[j]);
1165
1166     res=CreateFileMoniker(relPath,ppmkRelPath);
1167
1168     for(j=0; tabStr1[j]!=NULL;j++)
1169         CoTaskMemFree(tabStr1[j]);
1170     for(j=0; tabStr2[j]!=NULL;j++)
1171         CoTaskMemFree(tabStr2[j]);
1172     CoTaskMemFree(tabStr1);
1173     CoTaskMemFree(tabStr2);
1174     CoTaskMemFree(str1);
1175     CoTaskMemFree(str2);
1176     HeapFree(GetProcessHeap(),0,relPath);
1177
1178     if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0))
1179         return MK_S_HIM;
1180
1181     return res;
1182 }
1183
1184 /******************************************************************************
1185  *        FileMoniker_GetDisplayName
1186  */
1187 static HRESULT WINAPI
1188 FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1189                                IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1190 {
1191     FileMonikerImpl *This = (FileMonikerImpl *)iface;
1192
1193     int len=lstrlenW(This->filePathName);
1194
1195     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1196
1197     if (ppszDisplayName==NULL)
1198         return E_POINTER;
1199
1200     if (pmkToLeft!=NULL)
1201         return E_INVALIDARG;
1202
1203     *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
1204     if (*ppszDisplayName==NULL)
1205         return E_OUTOFMEMORY;
1206
1207     strcpyW(*ppszDisplayName,This->filePathName);
1208
1209     TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
1210     
1211     return S_OK;
1212 }
1213
1214 /******************************************************************************
1215  *        FileMoniker_ParseDisplayName
1216  */
1217 static HRESULT WINAPI
1218 FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
1219                      LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
1220 {
1221     FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
1222     return E_NOTIMPL;
1223 }
1224
1225 /******************************************************************************
1226  *        FileMoniker_IsSystemMoniker
1227  */
1228 static HRESULT WINAPI
1229 FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1230 {
1231     TRACE("(%p,%p)\n",iface,pwdMksys);
1232
1233     if (!pwdMksys)
1234         return E_POINTER;
1235
1236     (*pwdMksys)=MKSYS_FILEMONIKER;
1237
1238     return S_OK;
1239 }
1240
1241 /*******************************************************************************
1242  *        FileMonikerIROTData_QueryInterface
1243  */
1244 static HRESULT WINAPI
1245 FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
1246 {
1247
1248     IMoniker *This = impl_from_IROTData(iface);
1249
1250     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1251
1252     return FileMonikerImpl_QueryInterface(This, riid, ppvObject);
1253 }
1254
1255 /***********************************************************************
1256  *        FileMonikerIROTData_AddRef
1257  */
1258 static ULONG WINAPI
1259 FileMonikerROTDataImpl_AddRef(IROTData *iface)
1260 {
1261     IMoniker *This = impl_from_IROTData(iface);
1262
1263     TRACE("(%p)\n",This);
1264
1265     return IMoniker_AddRef(This);
1266 }
1267
1268 /***********************************************************************
1269  *        FileMonikerIROTData_Release
1270  */
1271 static ULONG WINAPI
1272 FileMonikerROTDataImpl_Release(IROTData* iface)
1273 {
1274     IMoniker *This = impl_from_IROTData(iface);
1275
1276     TRACE("(%p)\n",This);
1277
1278     return FileMonikerImpl_Release(This);
1279 }
1280
1281 /******************************************************************************
1282  *        FileMonikerIROTData_GetComparisonData
1283  */
1284 static HRESULT WINAPI
1285 FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData,
1286                                           ULONG cbMax, ULONG* pcbData)
1287 {
1288     IMoniker *This = impl_from_IROTData(iface);
1289     FileMonikerImpl *This1 = (FileMonikerImpl *)This;
1290     int len = (strlenW(This1->filePathName)+1);
1291     int i;
1292     LPWSTR pszFileName;
1293
1294     TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1295
1296     *pcbData = sizeof(CLSID) + len * sizeof(WCHAR);
1297     if (cbMax < *pcbData)
1298         return E_OUTOFMEMORY;
1299
1300     memcpy(pbData, &CLSID_FileMoniker, sizeof(CLSID));
1301     pszFileName = (LPWSTR)(pbData+sizeof(CLSID));
1302     for (i = 0; i < len; i++)
1303         pszFileName[i] = toupperW(This1->filePathName[i]);
1304
1305     return S_OK;
1306 }
1307
1308 /*
1309  * Virtual function table for the FileMonikerImpl class which include IPersist,
1310  * IPersistStream and IMoniker functions.
1311  */
1312 static const IMonikerVtbl VT_FileMonikerImpl =
1313 {
1314     FileMonikerImpl_QueryInterface,
1315     FileMonikerImpl_AddRef,
1316     FileMonikerImpl_Release,
1317     FileMonikerImpl_GetClassID,
1318     FileMonikerImpl_IsDirty,
1319     FileMonikerImpl_Load,
1320     FileMonikerImpl_Save,
1321     FileMonikerImpl_GetSizeMax,
1322     FileMonikerImpl_BindToObject,
1323     FileMonikerImpl_BindToStorage,
1324     FileMonikerImpl_Reduce,
1325     FileMonikerImpl_ComposeWith,
1326     FileMonikerImpl_Enum,
1327     FileMonikerImpl_IsEqual,
1328     FileMonikerImpl_Hash,
1329     FileMonikerImpl_IsRunning,
1330     FileMonikerImpl_GetTimeOfLastChange,
1331     FileMonikerImpl_Inverse,
1332     FileMonikerImpl_CommonPrefixWith,
1333     FileMonikerImpl_RelativePathTo,
1334     FileMonikerImpl_GetDisplayName,
1335     FileMonikerImpl_ParseDisplayName,
1336     FileMonikerImpl_IsSystemMoniker
1337 };
1338
1339 /* Virtual function table for the IROTData class. */
1340 static const IROTDataVtbl VT_ROTDataImpl =
1341 {
1342     FileMonikerROTDataImpl_QueryInterface,
1343     FileMonikerROTDataImpl_AddRef,
1344     FileMonikerROTDataImpl_Release,
1345     FileMonikerROTDataImpl_GetComparisonData
1346 };
1347
1348 /******************************************************************************
1349  *         FileMoniker_Construct (local function)
1350  */
1351 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
1352 {
1353     int nb=0,i;
1354     int sizeStr=lstrlenW(lpszPathName);
1355     LPOLESTR *tabStr=0;
1356     static const WCHAR twoPoint[]={'.','.',0};
1357     static const WCHAR bkSlash[]={'\\',0};
1358     BYTE addBkSlash;
1359
1360     TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName));
1361
1362     /* Initialize the virtual function table. */
1363     This->lpvtbl1      = &VT_FileMonikerImpl;
1364     This->lpvtbl2      = &VT_ROTDataImpl;
1365     This->ref          = 0;
1366     This->pMarshal     = NULL;
1367
1368     This->filePathName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1));
1369
1370     if (This->filePathName==NULL)
1371         return E_OUTOFMEMORY;
1372
1373     strcpyW(This->filePathName,lpszPathName);
1374
1375     nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr);
1376
1377     if (nb > 0 ){
1378
1379         addBkSlash=1;
1380         if (lstrcmpW(tabStr[0],twoPoint)!=0)
1381             addBkSlash=0;
1382         else
1383             for(i=0;i<nb;i++){
1384
1385                 if ( (lstrcmpW(tabStr[i],twoPoint)!=0) && (lstrcmpW(tabStr[i],bkSlash)!=0) ){
1386                     addBkSlash=0;
1387                     break;
1388                 }
1389                 else
1390
1391                     if (lstrcmpW(tabStr[i],bkSlash)==0 && i<nb-1 && lstrcmpW(tabStr[i+1],bkSlash)==0){
1392                         *tabStr[i]=0;
1393                         sizeStr--;
1394                         addBkSlash=0;
1395                         break;
1396                     }
1397             }
1398
1399         if (lstrcmpW(tabStr[nb-1],bkSlash)==0)
1400             addBkSlash=0;
1401
1402         This->filePathName=HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR));
1403
1404         *This->filePathName=0;
1405
1406         for(i=0;tabStr[i]!=NULL;i++)
1407             strcatW(This->filePathName,tabStr[i]);
1408
1409         if (addBkSlash)
1410             strcatW(This->filePathName,bkSlash);
1411     }
1412
1413     for(i=0; tabStr[i]!=NULL;i++)
1414         CoTaskMemFree(tabStr[i]);
1415     CoTaskMemFree(tabStr);
1416
1417     return S_OK;
1418 }
1419
1420 /******************************************************************************
1421  *        CreateFileMoniker (OLE32.@)
1422  ******************************************************************************/
1423 HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk)
1424 {
1425     FileMonikerImpl* newFileMoniker;
1426     HRESULT  hr;
1427
1428     TRACE("(%s,%p)\n",debugstr_w(lpszPathName),ppmk);
1429
1430     if (!ppmk)
1431         return E_POINTER;
1432
1433     if(!lpszPathName)
1434         return MK_E_SYNTAX;
1435
1436     *ppmk=NULL;
1437
1438     newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
1439
1440     if (!newFileMoniker)
1441         return E_OUTOFMEMORY;
1442
1443     hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName);
1444
1445     if (SUCCEEDED(hr))
1446         hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker,&IID_IMoniker,(void**)ppmk);
1447     else
1448         HeapFree(GetProcessHeap(),0,newFileMoniker);
1449
1450     return hr;
1451 }
1452
1453 /* find a character from a set in reverse without the string having to be null-terminated */
1454 static inline WCHAR *memrpbrkW(const WCHAR *ptr, size_t n, const WCHAR *accept)
1455 {
1456     const WCHAR *end, *ret = NULL;
1457     for (end = ptr + n; ptr < end; ptr++) if (strchrW(accept, *ptr)) ret = ptr;
1458     return (WCHAR *)ret;
1459 }
1460
1461 HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
1462                                           LPDWORD pchEaten, LPMONIKER *ppmk)
1463 {
1464     LPCWSTR end;
1465     static const WCHAR wszSeparators[] = {':','\\','/','!',0};
1466
1467     for (end = szDisplayName + strlenW(szDisplayName);
1468          end && (end != szDisplayName);
1469          end = memrpbrkW(szDisplayName, end - szDisplayName, wszSeparators))
1470     {
1471         HRESULT hr;
1472         IRunningObjectTable *rot;
1473         IMoniker *file_moniker;
1474         LPWSTR file_display_name;
1475         LPWSTR full_path_name;
1476         DWORD full_path_name_len;
1477         int len = end - szDisplayName;
1478
1479         file_display_name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1480         if (!file_display_name) return E_OUTOFMEMORY;
1481         memcpy(file_display_name, szDisplayName, len * sizeof(WCHAR));
1482         file_display_name[len] = '\0';
1483
1484         hr = CreateFileMoniker(file_display_name, &file_moniker);
1485         if (FAILED(hr))
1486         {
1487             HeapFree(GetProcessHeap(), 0, file_display_name);
1488             return hr;
1489         }
1490
1491         hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
1492         if (FAILED(hr))
1493         {
1494             HeapFree(GetProcessHeap(), 0, file_display_name);
1495             IMoniker_Release(file_moniker);
1496             return hr;
1497         }
1498
1499         hr = IRunningObjectTable_IsRunning(rot, file_moniker);
1500         IRunningObjectTable_Release(rot);
1501         if (FAILED(hr))
1502         {
1503             HeapFree(GetProcessHeap(), 0, file_display_name);
1504             IMoniker_Release(file_moniker);
1505             return hr;
1506         }
1507         if (hr == S_OK)
1508         {
1509             TRACE("found running file moniker for %s\n", debugstr_w(file_display_name));
1510             *pchEaten = len;
1511             *ppmk = file_moniker;
1512             HeapFree(GetProcessHeap(), 0, file_display_name);
1513             return S_OK;
1514         }
1515
1516         full_path_name_len = GetFullPathNameW(file_display_name, 0, NULL, NULL);
1517         if (!full_path_name_len)
1518         {
1519             HeapFree(GetProcessHeap(), 0, file_display_name);
1520             IMoniker_Release(file_moniker);
1521             return MK_E_SYNTAX;
1522         }
1523         full_path_name = HeapAlloc(GetProcessHeap(), 0, full_path_name_len * sizeof(WCHAR));
1524         if (!full_path_name)
1525         {
1526             HeapFree(GetProcessHeap(), 0, file_display_name);
1527             IMoniker_Release(file_moniker);
1528             return E_OUTOFMEMORY;
1529         }
1530         GetFullPathNameW(file_display_name, full_path_name_len, full_path_name, NULL);
1531
1532         if (GetFileAttributesW(full_path_name) == INVALID_FILE_ATTRIBUTES)
1533             TRACE("couldn't open file %s\n", debugstr_w(full_path_name));
1534         else
1535         {
1536             TRACE("got file moniker for %s\n", debugstr_w(szDisplayName));
1537             *pchEaten = len;
1538             *ppmk = file_moniker;
1539             HeapFree(GetProcessHeap(), 0, file_display_name);
1540             HeapFree(GetProcessHeap(), 0, full_path_name);
1541             return S_OK;
1542         }
1543         HeapFree(GetProcessHeap(), 0, file_display_name);
1544         HeapFree(GetProcessHeap(), 0, full_path_name);
1545         IMoniker_Release(file_moniker);
1546     }
1547
1548     return MK_E_CANTOPENFILE;
1549 }
1550
1551
1552 static HRESULT WINAPI FileMonikerCF_QueryInterface(LPCLASSFACTORY iface,
1553                                                   REFIID riid, LPVOID *ppv)
1554 {
1555     *ppv = NULL;
1556     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1557     {
1558         *ppv = iface;
1559         IUnknown_AddRef(iface);
1560         return S_OK;
1561     }
1562     return E_NOINTERFACE;
1563 }
1564
1565 static ULONG WINAPI FileMonikerCF_AddRef(LPCLASSFACTORY iface)
1566 {
1567     return 2; /* non-heap based object */
1568 }
1569
1570 static ULONG WINAPI FileMonikerCF_Release(LPCLASSFACTORY iface)
1571 {
1572     return 1; /* non-heap based object */
1573 }
1574
1575 static HRESULT WINAPI FileMonikerCF_CreateInstance(LPCLASSFACTORY iface,
1576     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1577 {
1578     FileMonikerImpl* newFileMoniker;
1579     HRESULT  hr;
1580     static const WCHAR wszEmpty[] = { 0 };
1581
1582     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1583
1584     *ppv = NULL;
1585
1586     if (pUnk)
1587         return CLASS_E_NOAGGREGATION;
1588
1589     newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
1590     if (!newFileMoniker)
1591         return E_OUTOFMEMORY;
1592
1593     hr = FileMonikerImpl_Construct(newFileMoniker, wszEmpty);
1594
1595     if (SUCCEEDED(hr))
1596         hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker, riid, ppv);
1597     if (FAILED(hr))
1598         HeapFree(GetProcessHeap(),0,newFileMoniker);
1599
1600     return hr;
1601 }
1602
1603 static HRESULT WINAPI FileMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
1604 {
1605     FIXME("(%d), stub!\n",fLock);
1606     return S_OK;
1607 }
1608
1609 static const IClassFactoryVtbl FileMonikerCFVtbl =
1610 {
1611     FileMonikerCF_QueryInterface,
1612     FileMonikerCF_AddRef,
1613     FileMonikerCF_Release,
1614     FileMonikerCF_CreateInstance,
1615     FileMonikerCF_LockServer
1616 };
1617 static const IClassFactoryVtbl *FileMonikerCF = &FileMonikerCFVtbl;
1618
1619 HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv)
1620 {
1621     return IClassFactory_QueryInterface((IClassFactory *)&FileMonikerCF, riid, ppv);
1622 }