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