2 * FileMonikers implementation
4 * Copyright 1999 Noomen Hamza
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.
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.
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
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
38 #include "compobj_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42 const CLSID CLSID_FileMoniker = {
43 0x303, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
46 /* filemoniker data structure */
47 typedef struct FileMonikerImpl{
49 IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
51 /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether
52 * two monikers are equal. That's whay IROTData interface is implemented by monikers.
54 IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
56 ULONG ref; /* reference counter for this object */
58 LPOLESTR filePathName; /* path string identified by this filemoniker */
62 /* IROTData prototype function */
63 static HRESULT WINAPI FileMonikerROTDataImpl_GetComparaisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData);
65 /* Local function used by filemoniker implementation */
66 static HRESULT WINAPI FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
67 static HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* iface);
69 /*******************************************************************************
70 * FileMoniker_QueryInterface
73 FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
75 FileMonikerImpl *This = (FileMonikerImpl *)iface;
77 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
79 /* Perform a sanity check on the parameters.*/
80 if ( (This==0) || (ppvObject==0) )
83 /* Initialize the return parameter */
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)
94 else if (IsEqualIID(&IID_IROTData, riid))
95 *ppvObject = (IROTData*)&(This->lpvtbl2);
97 /* Check that we obtained an interface.*/
101 /* Query Interface always increases the reference count by one when it is successful */
102 IMoniker_AddRef(iface);
107 /******************************************************************************
111 FileMonikerImpl_AddRef(IMoniker* iface)
113 FileMonikerImpl *This = (FileMonikerImpl *)iface;
115 TRACE("(%p)\n",iface);
117 return InterlockedIncrement(&This->ref);
120 /******************************************************************************
121 * FileMoniker_Release
124 FileMonikerImpl_Release(IMoniker* iface)
126 FileMonikerImpl *This = (FileMonikerImpl *)iface;
129 TRACE("(%p)\n",iface);
131 ref = InterlockedDecrement(&This->ref);
133 /* destroy the object if there's no more reference on it */
134 if (ref == 0) FileMonikerImpl_Destroy(This);
139 /******************************************************************************
140 * FileMoniker_GetClassID
142 static HRESULT WINAPI
143 FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID)
145 TRACE("(%p,%p)\n",iface,pClassID);
150 *pClassID = CLSID_FileMoniker;
155 /******************************************************************************
156 * FileMoniker_IsDirty
158 * Note that the OLE-provided implementations of the IPersistStream::IsDirty
159 * method in the OLE-provided moniker interfaces always return S_FALSE because
160 * their internal state never changes.
162 static HRESULT WINAPI
163 FileMonikerImpl_IsDirty(IMoniker* iface)
166 TRACE("(%p)\n",iface);
171 /******************************************************************************
174 * this function locates and reads from the stream the filePath string
175 * written by FileMonikerImpl_Save
177 static HRESULT WINAPI
178 FileMonikerImpl_Load(IMoniker* iface,IStream* pStm)
185 DWORD dwbuffer,length,i,doubleLenHex,doubleLenDec;
187 FileMonikerImpl *This = (FileMonikerImpl *)iface;
189 TRACE("(%p,%p)\n",iface,pStm);
191 /* first WORD is non significative */
192 res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
193 if (bread!=sizeof(WORD) || wbuffer!=0)
196 /* read filePath string length (plus one) */
197 res=IStream_Read(pStm,&length,sizeof(DWORD),&bread);
198 if (bread != sizeof(DWORD))
201 /* read filePath string */
202 filePathA=HeapAlloc(GetProcessHeap(),0,length);
203 res=IStream_Read(pStm,filePathA,length,&bread);
204 HeapFree(GetProcessHeap(),0,filePathA);
208 /* read the first constant */
209 IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
210 if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF)
216 res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
217 if (bread!=sizeof(WORD) || wbuffer!=0)
224 doubleLenHex=doubleLenDec=2*length;
228 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
229 if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenDec)
235 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
236 if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenHex)
239 res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
240 if (bread!=sizeof(WORD) || wbuffer!=0x3)
243 filePathW=HeapAlloc(GetProcessHeap(),0,(length+1)*sizeof(WCHAR));
245 res=IStream_Read(pStm,filePathW,doubleLenHex,&bread);
246 if (bread!=doubleLenHex) {
247 HeapFree(GetProcessHeap(), 0, filePathW);
251 HeapFree(GetProcessHeap(),0,This->filePathName);
253 This->filePathName=filePathW;
258 /******************************************************************************
261 * This function saves data of this object. In the beginning I thougth
262 * that I have just to write the filePath string on Stream. But, when I
263 * tested this function whith windows programs samples, I noticed that it
264 * was not the case. So I analysed data written by this function on
265 * Windows and what this did function exactly ! But I have no idea about
267 * I guessed data which must be written on stream is:
268 * 1) WORD constant:zero
269 * 2) length of the path string ("\0" included)
270 * 3) path string type A
271 * 4) DWORD constant : 0xDEADFFFF
272 * 5) ten WORD constant: zero
273 * 6) DWORD: double-length of the the path string type W ("\0" not
275 * 7) WORD constant: 0x3
276 * 8) filePath unicode string.
277 * if the length(filePath) > 8 or length(filePath) == 8 stop at step 5)
279 static HRESULT WINAPI
280 FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
282 FileMonikerImpl *This = (FileMonikerImpl *)iface;
285 LPOLESTR filePathW=This->filePathName;
289 DWORD constant1 = 0xDEADFFFF; /* these constants are detected after analysing the data structure written by */
290 WORD constant2 = 0x3; /* FileMoniker_Save function in a windows program system */
297 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
302 /* write a DWORD set to 0 : constant */
303 res=IStream_Write(pStm,&zero,sizeof(WORD),NULL);
305 /* write length of filePath string ( "\0" included )*/
306 len = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
307 res=IStream_Write(pStm,&len,sizeof(DWORD),NULL);
309 /* write filePath string type A */
310 filePathA=HeapAlloc(GetProcessHeap(),0,len);
311 WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, len, NULL, NULL );
312 res=IStream_Write(pStm,filePathA,len,NULL);
313 HeapFree(GetProcessHeap(),0,filePathA);
315 /* write a DWORD set to 0xDEADFFFF: constant */
316 res=IStream_Write(pStm,&constant1,sizeof(DWORD),NULL);
319 /* write 10 times a DWORD set to 0 : constants */
321 res=IStream_Write(pStm,&zero,sizeof(WORD),NULL);
326 doubleLenHex=doubleLenDec=2*len;
330 /* write double-length of the path string ( "\0" included )*/
331 res=IStream_Write(pStm,&doubleLenDec,sizeof(DWORD),NULL);
336 /* write double-length (hexa representation) of the path string ( "\0" included ) */
337 res=IStream_Write(pStm,&doubleLenHex,sizeof(DWORD),NULL);
339 /* write a WORD set to 0x3: constant */
340 res=IStream_Write(pStm,&constant2,sizeof(WORD),NULL);
342 /* write path unicode string */
343 res=IStream_Write(pStm,filePathW,doubleLenHex,NULL);
348 /******************************************************************************
349 * FileMoniker_GetSizeMax
351 static HRESULT WINAPI
352 FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
354 FileMonikerImpl *This = (FileMonikerImpl *)iface;
355 DWORD len=lstrlenW(This->filePathName);
358 TRACE("(%p,%p)\n",iface,pcbSize);
363 /* for more details see FileMonikerImpl_Save coments */
365 sizeMAx = sizeof(WORD) + /* first WORD is 0 */
366 sizeof(DWORD)+ /* length of filePath including "\0" in the end of the string */
367 (len+1)+ /* filePath string */
368 sizeof(DWORD)+ /* constant : 0xDEADFFFF */
369 10*sizeof(WORD)+ /* 10 zero WORD */
370 sizeof(DWORD); /* size of the unicode filePath: "\0" not included */
372 if (len==0 || len > 8)
375 sizeMAx += sizeof(DWORD)+ /* size of the unicode filePath: "\0" not included */
376 sizeof(WORD)+ /* constant : 0x3 */
377 len*sizeof(WCHAR); /* unicde filePath string */
379 pcbSize->u.LowPart=sizeMAx;
380 pcbSize->u.HighPart=0;
385 /******************************************************************************
386 * FileMoniker_Destroy (local function)
387 *******************************************************************************/
388 HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* This)
390 TRACE("(%p)\n",This);
392 HeapFree(GetProcessHeap(),0,This->filePathName);
393 HeapFree(GetProcessHeap(),0,This);
398 /******************************************************************************
399 * FileMoniker_BindToObject
401 static HRESULT WINAPI
402 FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
403 REFIID riid, VOID** ppvResult)
408 IRunningObjectTable *prot=0;
410 IClassFactory *pcf=0;
411 IClassActivator *pca=0;
413 FileMonikerImpl *This = (FileMonikerImpl *)iface;
417 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
421 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
424 /* if the requested class was loaded before ! we don't need to reload it */
425 res = IRunningObjectTable_GetObject(prot,iface,&pObj);
428 /* first activation of this class */
429 res=GetClassFile(This->filePathName,&clsID);
432 res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IPersistFile,(void**)&ppf);
435 res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
439 IUnknown_AddRef(pObj);
447 res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf);
449 if (res==E_NOINTERFACE){
451 res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
453 if (res==E_NOINTERFACE)
454 return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
458 IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)ppf);
460 res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
465 IUnknown_AddRef(pObj);
472 /*res=GetClassFile(This->filePathName,&clsID);
476 res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf);
481 IUnknown_AddRef(pObj);
488 /* get the requested interface from the loaded class */
489 res= IUnknown_QueryInterface(pObj,riid,ppvResult);
491 IBindCtx_RegisterObjectBound(pbc,(IUnknown*)*ppvResult);
493 IUnknown_Release(pObj);
497 IRunningObjectTable_Release(prot);
500 IPersistFile_Release(ppf);
503 IClassActivator_Release(pca);
506 IClassFactory_Release(pcf);
511 /******************************************************************************
512 * FileMoniker_BindToStorage
514 static HRESULT WINAPI
515 FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
516 REFIID riid, VOID** ppvObject)
522 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
524 if (pmkToLeft==NULL){
526 if (IsEqualIID(&IID_IStorage, riid)){
528 /* get the file name */
529 IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath);
531 /* verifie if the file contains a storage object */
532 res=StgIsStorageFile(filePath);
536 res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
542 IStorage_AddRef(pstg);
547 CoTaskMemFree(filePath);
550 if ( (IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)) )
553 return E_NOINTERFACE;
557 FIXME("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
564 /******************************************************************************
566 ******************************************************************************/
567 static HRESULT WINAPI
568 FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
569 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
571 TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
573 if (ppmkReduced==NULL)
576 IMoniker_AddRef(iface);
580 return MK_S_REDUCED_TO_SELF;
583 /******************************************************************************
584 * FileMoniker_ComposeWith
586 static HRESULT WINAPI
587 FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
588 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
591 LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0;
592 static const WCHAR twoPoint[]={'.','.',0};
593 static const WCHAR bkSlash[]={'\\',0};
595 int i=0,j=0,lastIdx1=0,lastIdx2=0;
598 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
600 if (ppmkComposite==NULL)
608 IMoniker_IsSystemMoniker(pmkRight,&mkSys);
610 /* check if we have two filemonikers to compose or not */
611 if(mkSys==MKSYS_FILEMONIKER){
613 CreateBindCtx(0,&bind);
615 IMoniker_GetDisplayName(iface,bind,NULL,&str1);
616 IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2);
618 /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */
619 lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1;
620 lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1;
622 if ((lastIdx1==-1 && lastIdx2>-1)||(lastIdx1==1 && lstrcmpW(strDec1[0],twoPoint)==0))
625 if(lstrcmpW(strDec1[lastIdx1],bkSlash)==0)
628 /* for etch "..\" in the left of str2 remove the right element from str1 */
629 for(i=0; ( (lastIdx1>=0) && (strDec2[i]!=NULL) && (lstrcmpW(strDec2[i],twoPoint)==0) ) ;i+=2){
634 /* the length of the composed path string is raised by the sum of the two paths lengths */
635 newStr=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1));
638 return E_OUTOFMEMORY;
640 /* new path is the concatenation of the rest of str1 and str2 */
641 for(*newStr=0,j=0;j<=lastIdx1;j++)
642 strcatW(newStr,strDec1[j]);
644 if ((strDec2[i]==NULL && lastIdx1>-1 && lastIdx2>-1) || lstrcmpW(strDec2[i],bkSlash)!=0)
645 strcatW(newStr,bkSlash);
647 for(j=i;j<=lastIdx2;j++)
648 strcatW(newStr,strDec2[j]);
650 /* create a new moniker with the new string */
651 res=CreateFileMoniker(newStr,ppmkComposite);
653 /* free all strings space memory used by this function */
654 HeapFree(GetProcessHeap(),0,newStr);
656 for(i=0; strDec1[i]!=NULL;i++)
657 CoTaskMemFree(strDec1[i]);
658 for(i=0; strDec2[i]!=NULL;i++)
659 CoTaskMemFree(strDec2[i]);
660 CoTaskMemFree(strDec1);
661 CoTaskMemFree(strDec2);
668 else if(mkSys==MKSYS_ANTIMONIKER){
673 else if (fOnlyIfNotGeneric){
676 return MK_E_NEEDGENERIC;
680 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
683 /******************************************************************************
686 static HRESULT WINAPI
687 FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
689 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
691 if (ppenumMoniker == NULL)
694 *ppenumMoniker = NULL;
699 /******************************************************************************
700 * FileMoniker_IsEqual
702 static HRESULT WINAPI
703 FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
705 FileMonikerImpl *This = (FileMonikerImpl *)iface;
711 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
713 if (pmkOtherMoniker==NULL)
716 IMoniker_GetClassID(pmkOtherMoniker,&clsid);
718 if (!IsEqualCLSID(&clsid,&CLSID_FileMoniker))
721 res = CreateBindCtx(0,&bind);
722 if (FAILED(res)) return res;
724 if (SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath))) {
725 int result = lstrcmpiW(filePath, This->filePathName);
726 CoTaskMemFree(filePath);
727 if ( result == 0 ) return S_OK;
733 /******************************************************************************
736 static HRESULT WINAPI
737 FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
739 FileMonikerImpl *This = (FileMonikerImpl *)iface;
741 int h = 0,i,skip,len;
748 val = This->filePathName;
752 for (i = len ; i > 0; i--) {
753 h = (h * 37) + val[off++];
756 /* only sample some characters */
758 for (i = len ; i > 0; i -= skip, off += skip) {
759 h = (h * 39) + val[off];
768 /******************************************************************************
769 * FileMoniker_IsRunning
771 static HRESULT WINAPI
772 FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
773 IMoniker* pmkNewlyRunning)
775 IRunningObjectTable* rot;
778 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
780 if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) )
786 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
791 res = IRunningObjectTable_IsRunning(rot,iface);
793 IRunningObjectTable_Release(rot);
798 /******************************************************************************
799 * FileMoniker_GetTimeOfLastChange
800 ******************************************************************************/
801 static HRESULT WINAPI
802 FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
803 IMoniker* pmkToLeft, FILETIME* pFileTime)
805 FileMonikerImpl *This = (FileMonikerImpl *)iface;
806 IRunningObjectTable* rot;
808 WIN32_FILE_ATTRIBUTE_DATA info;
810 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime);
818 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
823 res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime);
825 if (FAILED(res)){ /* the moniker is not registered */
827 if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info))
828 return MK_E_NOOBJECT;
830 *pFileTime=info.ftLastWriteTime;
836 /******************************************************************************
837 * FileMoniker_Inverse
839 static HRESULT WINAPI
840 FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
842 TRACE("(%p,%p)\n",iface,ppmk);
844 return CreateAntiMoniker(ppmk);
847 /******************************************************************************
848 * FileMoniker_CommonPrefixWith
850 static HRESULT WINAPI
851 FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
854 LPOLESTR pathThis,pathOther,*stringTable1,*stringTable2,commonPath;
857 ULONG nb1,nb2,i,sameIdx;
858 BOOL machimeNameCase=FALSE;
860 if (ppmkPrefix==NULL)
868 /* check if we have the same type of moniker */
869 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
871 if(mkSys==MKSYS_FILEMONIKER){
874 CreateBindCtx(0,&pbind);
876 /* create a string based on common part of the two paths */
878 IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis);
879 IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther);
881 nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1);
882 nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2);
884 if (nb1==0 || nb2==0)
885 return MK_E_NOPREFIX;
887 commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1));
891 for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) &&
892 (stringTable2[sameIdx]!=NULL) &&
893 (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++);
895 if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){
897 machimeNameCase=TRUE;
899 for(i=2;i<sameIdx;i++)
901 if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){
902 machimeNameCase=FALSE;
907 if (machimeNameCase && *stringTable1[sameIdx-1]=='\\')
910 if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
914 for(i=0;i<sameIdx;i++)
915 strcatW(commonPath,stringTable1[i]);
918 CoTaskMemFree(stringTable1[i]);
920 CoTaskMemFree(stringTable1);
923 CoTaskMemFree(stringTable2[i]);
925 CoTaskMemFree(stringTable2);
927 ret = CreateFileMoniker(commonPath,ppmkPrefix);
929 HeapFree(GetProcessHeap(),0,commonPath);
933 return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
936 /******************************************************************************
937 * DecomposePath (local function)
939 int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable)
941 static const WCHAR bSlash[] = {'\\',0};
942 WCHAR word[MAX_PATH];
943 int i=0,j,tabIndex=0;
944 LPOLESTR *strgtable ;
946 int len=lstrlenW(str);
948 TRACE("%s, %p\n", debugstr_w(str), *stringTable);
950 strgtable =CoTaskMemAlloc(len*sizeof(LPOLESTR));
953 return E_OUTOFMEMORY;
957 if(str[i]==bSlash[0]){
959 strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR));
961 if (strgtable[tabIndex]==NULL)
962 return E_OUTOFMEMORY;
964 strcpyW(strgtable[tabIndex++],bSlash);
971 for(j=0; str[i]!=0 && str[i]!=bSlash[0] ; i++,j++)
976 strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1));
978 if (strgtable[tabIndex]==NULL)
979 return E_OUTOFMEMORY;
981 strcpyW(strgtable[tabIndex++],word);
984 strgtable[tabIndex]=NULL;
986 *stringTable=strgtable;
991 /******************************************************************************
992 * FileMoniker_RelativePathTo
994 static HRESULT WINAPI
995 FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
999 LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
1000 DWORD len1=0,len2=0,sameIdx=0,j=0;
1001 static const WCHAR back[] ={'.','.','\\',0};
1003 TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
1005 if (ppmkRelPath==NULL)
1009 return E_INVALIDARG;
1011 res=CreateBindCtx(0,&bind);
1015 res=IMoniker_GetDisplayName(iface,bind,NULL,&str1);
1018 res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2);
1022 len1=FileMonikerImpl_DecomposePath(str1,&tabStr1);
1023 len2=FileMonikerImpl_DecomposePath(str2,&tabStr2);
1025 if (FAILED(len1) || FAILED(len2))
1026 return E_OUTOFMEMORY;
1028 /* count the number of similar items from the begin of the two paths */
1029 for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) &&
1030 (tabStr2[sameIdx]!=NULL) &&
1031 (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++);
1033 /* begin the construction of relativePath */
1034 /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */
1035 /* by "..\\" in the begin */
1036 relPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2)));
1040 if (len2>0 && !(len1==1 && len2==1 && sameIdx==0))
1041 for(j=sameIdx;(tabStr1[j] != NULL); j++)
1042 if (*tabStr1[j]!='\\')
1043 strcatW(relPath,back);
1045 /* add items of the second path (similar items with the first path are not included) to the relativePath */
1046 for(j=sameIdx;tabStr2[j]!=NULL;j++)
1047 strcatW(relPath,tabStr2[j]);
1049 res=CreateFileMoniker(relPath,ppmkRelPath);
1051 for(j=0; tabStr1[j]!=NULL;j++)
1052 CoTaskMemFree(tabStr1[j]);
1053 for(j=0; tabStr2[j]!=NULL;j++)
1054 CoTaskMemFree(tabStr2[j]);
1055 CoTaskMemFree(tabStr1);
1056 CoTaskMemFree(tabStr2);
1057 CoTaskMemFree(str1);
1058 CoTaskMemFree(str2);
1059 HeapFree(GetProcessHeap(),0,relPath);
1061 if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0))
1067 /******************************************************************************
1068 * FileMoniker_GetDisplayName
1070 static HRESULT WINAPI
1071 FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1072 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1074 FileMonikerImpl *This = (FileMonikerImpl *)iface;
1076 int len=lstrlenW(This->filePathName);
1078 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1080 if (ppszDisplayName==NULL)
1083 if (pmkToLeft!=NULL)
1084 return E_INVALIDARG;
1086 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
1087 if (*ppszDisplayName==NULL)
1088 return E_OUTOFMEMORY;
1090 strcpyW(*ppszDisplayName,This->filePathName);
1092 TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
1097 /******************************************************************************
1098 * FileMoniker_ParseDisplayName
1100 static HRESULT WINAPI
1101 FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
1102 LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
1104 FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
1108 /******************************************************************************
1109 * FileMoniker_IsSystemMoniker
1111 static HRESULT WINAPI
1112 FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1114 TRACE("(%p,%p)\n",iface,pwdMksys);
1119 (*pwdMksys)=MKSYS_FILEMONIKER;
1124 /*******************************************************************************
1125 * FileMonikerIROTData_QueryInterface
1127 static HRESULT WINAPI
1128 FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
1131 ICOM_THIS_From_IROTData(IMoniker, iface);
1133 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1135 return FileMonikerImpl_QueryInterface(This, riid, ppvObject);
1138 /***********************************************************************
1139 * FileMonikerIROTData_AddRef
1142 FileMonikerROTDataImpl_AddRef(IROTData *iface)
1144 ICOM_THIS_From_IROTData(IMoniker, iface);
1146 TRACE("(%p)\n",This);
1148 return IMoniker_AddRef(This);
1151 /***********************************************************************
1152 * FileMonikerIROTData_Release
1155 FileMonikerROTDataImpl_Release(IROTData* iface)
1157 ICOM_THIS_From_IROTData(IMoniker, iface);
1159 TRACE("(%p)\n",This);
1161 return FileMonikerImpl_Release(This);
1164 /******************************************************************************
1165 * FileMonikerIROTData_GetComparaisonData
1167 static HRESULT WINAPI
1168 FileMonikerROTDataImpl_GetComparaisonData(IROTData* iface, BYTE* pbData,
1169 ULONG cbMax, ULONG* pcbData)
1171 FIXME("(),stub!\n");
1176 * Virtual function table for the FileMonikerImpl class which include IPersist,
1177 * IPersistStream and IMoniker functions.
1179 static IMonikerVtbl VT_FileMonikerImpl =
1181 FileMonikerImpl_QueryInterface,
1182 FileMonikerImpl_AddRef,
1183 FileMonikerImpl_Release,
1184 FileMonikerImpl_GetClassID,
1185 FileMonikerImpl_IsDirty,
1186 FileMonikerImpl_Load,
1187 FileMonikerImpl_Save,
1188 FileMonikerImpl_GetSizeMax,
1189 FileMonikerImpl_BindToObject,
1190 FileMonikerImpl_BindToStorage,
1191 FileMonikerImpl_Reduce,
1192 FileMonikerImpl_ComposeWith,
1193 FileMonikerImpl_Enum,
1194 FileMonikerImpl_IsEqual,
1195 FileMonikerImpl_Hash,
1196 FileMonikerImpl_IsRunning,
1197 FileMonikerImpl_GetTimeOfLastChange,
1198 FileMonikerImpl_Inverse,
1199 FileMonikerImpl_CommonPrefixWith,
1200 FileMonikerImpl_RelativePathTo,
1201 FileMonikerImpl_GetDisplayName,
1202 FileMonikerImpl_ParseDisplayName,
1203 FileMonikerImpl_IsSystemMoniker
1206 /* Virtual function table for the IROTData class. */
1207 static IROTDataVtbl VT_ROTDataImpl =
1209 FileMonikerROTDataImpl_QueryInterface,
1210 FileMonikerROTDataImpl_AddRef,
1211 FileMonikerROTDataImpl_Release,
1212 FileMonikerROTDataImpl_GetComparaisonData
1215 /******************************************************************************
1216 * FileMoniker_Construct (local function)
1218 static HRESULT WINAPI
1219 FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
1222 int sizeStr=lstrlenW(lpszPathName);
1224 static const WCHAR twoPoint[]={'.','.',0};
1225 static const WCHAR bkSlash[]={'\\',0};
1228 TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName));
1230 /* Initialize the virtual fgunction table. */
1231 This->lpvtbl1 = &VT_FileMonikerImpl;
1232 This->lpvtbl2 = &VT_ROTDataImpl;
1235 This->filePathName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1));
1237 if (This->filePathName==NULL)
1238 return E_OUTOFMEMORY;
1240 strcpyW(This->filePathName,lpszPathName);
1242 nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr);
1247 if (lstrcmpW(tabStr[0],twoPoint)!=0)
1252 if ( (lstrcmpW(tabStr[i],twoPoint)!=0) && (lstrcmpW(tabStr[i],bkSlash)!=0) ){
1258 if (lstrcmpW(tabStr[i],bkSlash)==0 && i<nb-1 && lstrcmpW(tabStr[i+1],bkSlash)==0){
1266 if (lstrcmpW(tabStr[nb-1],bkSlash)==0)
1269 This->filePathName=HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR));
1271 *This->filePathName=0;
1273 for(i=0;tabStr[i]!=NULL;i++)
1274 strcatW(This->filePathName,tabStr[i]);
1277 strcatW(This->filePathName,bkSlash);
1280 for(i=0; tabStr[i]!=NULL;i++)
1281 CoTaskMemFree(tabStr[i]);
1282 CoTaskMemFree(tabStr);
1287 /******************************************************************************
1288 * CreateFileMoniker (OLE32.@)
1289 ******************************************************************************/
1290 HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk)
1292 FileMonikerImpl* newFileMoniker;
1295 TRACE("(%s,%p)\n",debugstr_w(lpszPathName),ppmk);
1305 newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
1307 if (!newFileMoniker)
1308 return E_OUTOFMEMORY;
1310 hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName);
1313 hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker,&IID_IMoniker,(void**)ppmk);
1315 HeapFree(GetProcessHeap(),0,newFileMoniker);