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