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