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