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