~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ole32/filemoniker.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.