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