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