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