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