ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

filemoniker.c
Go to the documentation of this file.
00001 /*
00002  * FileMonikers implementation
00003  *
00004  * Copyright 1999  Noomen Hamza
00005  * Copyright 2007  Robert Shearman
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include <assert.h>
00023 #include <stdarg.h>
00024 #include <string.h>
00025 
00026 #define COBJMACROS
00027 #define NONAMELESSUNION
00028 #define NONAMELESSSTRUCT
00029 
00030 #include "windef.h"
00031 #include "winbase.h"
00032 #include "winerror.h"
00033 #include "winnls.h"
00034 #include "wine/unicode.h"
00035 #include "wine/debug.h"
00036 #include "objbase.h"
00037 #include "moniker.h"
00038 
00039 #include "compobj_private.h"
00040 
00041 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00042 
00043 /* filemoniker data structure */
00044 typedef struct FileMonikerImpl{
00045     IMoniker IMoniker_iface;
00046     IROTData IROTData_iface;
00047     LONG ref;
00048     LPOLESTR filePathName; /* path string identified by this filemoniker */
00049     IUnknown *pMarshal; /* custom marshaler */
00050 } FileMonikerImpl;
00051 
00052 static inline FileMonikerImpl *impl_from_IMoniker(IMoniker *iface)
00053 {
00054     return CONTAINING_RECORD(iface, FileMonikerImpl, IMoniker_iface);
00055 }
00056 
00057 static inline FileMonikerImpl *impl_from_IROTData(IROTData *iface)
00058 {
00059     return CONTAINING_RECORD(iface, FileMonikerImpl, IROTData_iface);
00060 }
00061 
00062 /* Local function used by filemoniker implementation */
00063 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
00064 static HRESULT FileMonikerImpl_Destroy(FileMonikerImpl* iface);
00065 
00066 /*******************************************************************************
00067  *        FileMoniker_QueryInterface
00068  */
00069 static HRESULT WINAPI
00070 FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
00071 {
00072     FileMonikerImpl *This = impl_from_IMoniker(iface);
00073 
00074     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
00075 
00076     /* Perform a sanity check on the parameters.*/
00077     if ( ppvObject==0 )
00078     return E_INVALIDARG;
00079 
00080     /* Initialize the return parameter */
00081     *ppvObject = 0;
00082 
00083     /* Compare the riid with the interface IDs implemented by this object.*/
00084     if (IsEqualIID(&IID_IUnknown, riid)      ||
00085         IsEqualIID(&IID_IPersist, riid)      ||
00086         IsEqualIID(&IID_IPersistStream,riid) ||
00087         IsEqualIID(&IID_IMoniker, riid)
00088        )
00089         *ppvObject = iface;
00090 
00091     else if (IsEqualIID(&IID_IROTData, riid))
00092         *ppvObject = &This->IROTData_iface;
00093     else if (IsEqualIID(&IID_IMarshal, riid))
00094     {
00095         HRESULT hr = S_OK;
00096         if (!This->pMarshal)
00097             hr = MonikerMarshal_Create(iface, &This->pMarshal);
00098         if (hr != S_OK)
00099             return hr;
00100         return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
00101     }
00102 
00103     /* Check that we obtained an interface.*/
00104     if ((*ppvObject)==0)
00105         return E_NOINTERFACE;
00106 
00107     /* Query Interface always increases the reference count by one when it is successful */
00108     IMoniker_AddRef(iface);
00109 
00110     return S_OK;
00111 }
00112 
00113 /******************************************************************************
00114  *        FileMoniker_AddRef
00115  */
00116 static ULONG WINAPI
00117 FileMonikerImpl_AddRef(IMoniker* iface)
00118 {
00119     FileMonikerImpl *This = impl_from_IMoniker(iface);
00120 
00121     TRACE("(%p)\n",iface);
00122 
00123     return InterlockedIncrement(&This->ref);
00124 }
00125 
00126 /******************************************************************************
00127  *        FileMoniker_Release
00128  */
00129 static ULONG WINAPI
00130 FileMonikerImpl_Release(IMoniker* iface)
00131 {
00132     FileMonikerImpl *This = impl_from_IMoniker(iface);
00133     ULONG ref;
00134 
00135     TRACE("(%p)\n",iface);
00136 
00137     ref = InterlockedDecrement(&This->ref);
00138 
00139     /* destroy the object if there's no more reference on it */
00140     if (ref == 0) FileMonikerImpl_Destroy(This);
00141 
00142     return ref;
00143 }
00144 
00145 /******************************************************************************
00146  *        FileMoniker_GetClassID
00147  */
00148 static HRESULT WINAPI
00149 FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID)
00150 {
00151     TRACE("(%p,%p)\n",iface,pClassID);
00152 
00153     if (pClassID==NULL)
00154         return E_POINTER;
00155 
00156     *pClassID = CLSID_FileMoniker;
00157 
00158     return S_OK;
00159 }
00160 
00161 /******************************************************************************
00162  *        FileMoniker_IsDirty
00163  *
00164  * Note that the OLE-provided implementations of the IPersistStream::IsDirty
00165  * method in the OLE-provided moniker interfaces always return S_FALSE because
00166  * their internal state never changes.
00167  */
00168 static HRESULT WINAPI
00169 FileMonikerImpl_IsDirty(IMoniker* iface)
00170 {
00171 
00172     TRACE("(%p)\n",iface);
00173 
00174     return S_FALSE;
00175 }
00176 
00177 /******************************************************************************
00178  *        FileMoniker_Load
00179  *
00180  * this function locates and reads from the stream the filePath string
00181  * written by FileMonikerImpl_Save
00182  */
00183 static HRESULT WINAPI
00184 FileMonikerImpl_Load(IMoniker* iface, IStream* pStm)
00185 {
00186     FileMonikerImpl *This = impl_from_IMoniker(iface);
00187     HRESULT res;
00188     CHAR* filePathA = NULL;
00189     WCHAR* filePathW = NULL;
00190     ULONG bread;
00191     WORD  wbuffer;
00192     DWORD dwbuffer, bytesA, bytesW, len;
00193     int i;
00194 
00195 
00196     TRACE("(%p,%p)\n",iface,pStm);
00197 
00198     /* first WORD */
00199     res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
00200     if (bread!=sizeof(WORD))
00201     {
00202         WARN("Couldn't read 0 word\n");
00203         goto fail;
00204     }
00205 
00206     /* read filePath string length (plus one) */
00207     res=IStream_Read(pStm,&bytesA,sizeof(DWORD),&bread);
00208     if (bread != sizeof(DWORD))
00209     {
00210         WARN("Couldn't read file string length\n");
00211         goto fail;
00212     }
00213 
00214     /* read filePath string */
00215     filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
00216     if (!filePathA)
00217     {
00218         res = E_OUTOFMEMORY;
00219         goto fail;
00220     }
00221 
00222     res=IStream_Read(pStm,filePathA,bytesA,&bread);
00223     if (bread != bytesA)
00224     {
00225         WARN("Couldn't read file path string\n");
00226         goto fail;
00227     }
00228 
00229     /* read the unknown value */
00230     IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
00231     if (bread != sizeof(WORD))
00232     {
00233         WARN("Couldn't read unknown value\n");
00234         goto fail;
00235     }
00236 
00237     /* read the DEAD constant */
00238     IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
00239     if (bread != sizeof(WORD))
00240     {
00241         WARN("Couldn't read DEAD constant\n");
00242         goto fail;
00243     }
00244 
00245     for(i=0;i<5;i++)
00246     {
00247         res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
00248         if (bread!=sizeof(DWORD))
00249         {
00250             WARN("Couldn't read 0 padding\n");
00251             goto fail;
00252         }
00253     }
00254 
00255     res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
00256     if (bread!=sizeof(DWORD))
00257         goto fail;
00258 
00259     if (!dwbuffer) /* No W-string */
00260     {        
00261         bytesA--;
00262         len=MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, bytesA, NULL, 0);
00263         if (!len)
00264             goto fail;
00265 
00266         filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
00267         if (!filePathW)
00268         {
00269             res = E_OUTOFMEMORY;
00270             goto fail;
00271         }
00272         MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, -1, filePathW, len+1);
00273         goto succeed;
00274     }
00275 
00276     if (dwbuffer < 6)
00277         goto fail;
00278 
00279     bytesW=dwbuffer - 6;
00280 
00281     res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
00282     if (bread!=sizeof(DWORD) || dwbuffer!=bytesW)
00283         goto fail;
00284 
00285     res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
00286     if (bread!=sizeof(WORD) || wbuffer!=0x3)
00287         goto fail;
00288 
00289     len=bytesW/sizeof(WCHAR);
00290     filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
00291     if(!filePathW)
00292     {
00293          res = E_OUTOFMEMORY;
00294          goto fail;
00295     }
00296     res=IStream_Read(pStm,filePathW,bytesW,&bread);
00297     if (bread!=bytesW)
00298          goto fail;
00299 
00300     filePathW[len]=0;
00301 
00302  succeed:
00303     HeapFree(GetProcessHeap(),0,filePathA);
00304     HeapFree(GetProcessHeap(),0,This->filePathName);
00305     This->filePathName=filePathW;
00306 
00307     return S_OK;
00308 
00309  fail:
00310     HeapFree(GetProcessHeap(), 0, filePathA);
00311     HeapFree(GetProcessHeap(), 0, filePathW);
00312 
00313     if (SUCCEEDED(res))
00314          res = E_FAIL;
00315     return res;
00316 }
00317 
00318 /******************************************************************************
00319  *        FileMoniker_Save
00320  *
00321  * This function saves data of this object. In the beginning I thought
00322  * that I have just to write the filePath string on Stream. But, when I
00323  * tested this function with windows program samples, I noticed that it
00324  * was not the case. This implementation is based on XP SP2. Other versions
00325  * of Windows have minor variations.
00326  *
00327  * Data which must be written on stream is:
00328  * 1) WORD constant: zero (not validated by Windows)
00329  * 2) length of the path string ("\0" included)
00330  * 3) path string type A
00331  * 4) Unknown WORD value: Frequently 0xFFFF, but not always. If set very large,
00332  *     Windows returns E_OUTOFMEMORY
00333  * 5) WORD Constant: 0xDEAD (not validated by Windows)
00334  * 6) five DWORD constant: zero (not validated by Windows)
00335  * 7) If we're only writing the multibyte version,
00336  *     write a zero DWORD and finish.
00337  *
00338  * 8) DWORD: double-length of the path string type W ("\0" not
00339  *    included)
00340  * 9) WORD constant: 0x3
00341  * 10) filePath unicode string.
00342  *
00343  */
00344 static HRESULT WINAPI
00345 FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
00346 {
00347     FileMonikerImpl *This = impl_from_IMoniker(iface);
00348     HRESULT res;
00349     LPOLESTR filePathW=This->filePathName;
00350     CHAR*    filePathA;
00351     DWORD bytesA, bytesW, len;
00352 
00353     static const WORD FFFF = 0xFFFF; /* Constants */
00354     static const WORD DEAD = 0xDEAD;
00355     static const DWORD ZERO     = 0;
00356     static const WORD  THREE    = 0x3;
00357 
00358     int i;
00359     BOOL bUsedDefault, bWriteWide;
00360 
00361     TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
00362 
00363     if (pStm==NULL)
00364         return E_POINTER;
00365 
00366     /* write a 0 WORD */
00367     res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
00368     if (FAILED(res)) return res;
00369 
00370     /* write length of filePath string ( 0 included )*/
00371     bytesA = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
00372     res=IStream_Write(pStm,&bytesA,sizeof(DWORD),NULL);
00373     if (FAILED(res)) return res;
00374 
00375     /* write A string (with '\0') */
00376     filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
00377     if (!filePathA)
00378         return E_OUTOFMEMORY;
00379     WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, bytesA, NULL, &bUsedDefault);
00380     res=IStream_Write(pStm,filePathA,bytesA,NULL);
00381     HeapFree(GetProcessHeap(),0,filePathA);
00382     if (FAILED(res)) return res;
00383 
00384     /* write a WORD 0xFFFF */
00385     res=IStream_Write(pStm,&FFFF,sizeof(WORD),NULL);
00386     if (FAILED(res)) return res;
00387 
00388     /* write a WORD 0xDEAD */
00389     res=IStream_Write(pStm,&DEAD,sizeof(WORD),NULL);
00390     if (FAILED(res)) return res;
00391 
00392     /* write 5 zero DWORDs */
00393     for(i=0;i<5;i++)
00394     {
00395         res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
00396         if (FAILED(res)) return res;
00397     }
00398 
00399     /* Write the wide version if:
00400      *    + couldn't convert to CP_ACP, 
00401      * or + it's a directory, 
00402      * or + there's a character > 0xFF 
00403      */
00404     len = lstrlenW(filePathW);
00405     bWriteWide = (bUsedDefault || (len > 0 && filePathW[len-1]=='\\' ));
00406     if (!bWriteWide)
00407     {
00408         WCHAR* pch;
00409         for(pch=filePathW;*pch;++pch) 
00410         {
00411             if (*pch > 0xFF)
00412             {
00413                 bWriteWide = TRUE;
00414                 break;
00415             }
00416         }
00417     }
00418 
00419     if (!bWriteWide)
00420         return IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
00421 
00422     /* write bytes needed for the filepathW (without 0) + 6 */
00423     bytesW = len*sizeof(WCHAR) + 6;
00424     res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
00425     if (FAILED(res)) return res;
00426 
00427     /* try again, without the extra 6 */
00428     bytesW -= 6;
00429     res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
00430     if (FAILED(res)) return res;
00431 
00432     /* write a WORD 3 */
00433     res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
00434     if (FAILED(res)) return res;
00435 
00436     /* write W string (no 0) */
00437     return IStream_Write(pStm,filePathW,bytesW,NULL);
00438 }
00439 
00440 /******************************************************************************
00441  *        FileMoniker_GetSizeMax
00442  */
00443 static HRESULT WINAPI
00444 FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
00445 {
00446     FileMonikerImpl *This = impl_from_IMoniker(iface);
00447 
00448     TRACE("(%p,%p)\n",iface,pcbSize);
00449 
00450     if (!pcbSize)
00451         return E_POINTER;
00452 
00453     /* We could calculate exactly (see ...::Save()) but instead
00454      * we'll make a quick over-estimate, like Windows (NT4, XP) does.
00455      */
00456     pcbSize->u.LowPart  = 0x38 + 4 * lstrlenW(This->filePathName);
00457     pcbSize->u.HighPart = 0;
00458 
00459     return S_OK;
00460 }
00461 
00462 /******************************************************************************
00463  *        FileMoniker_Destroy (local function)
00464  *******************************************************************************/
00465 HRESULT FileMonikerImpl_Destroy(FileMonikerImpl* This)
00466 {
00467     TRACE("(%p)\n",This);
00468 
00469     if (This->pMarshal) IUnknown_Release(This->pMarshal);
00470     HeapFree(GetProcessHeap(),0,This->filePathName);
00471     HeapFree(GetProcessHeap(),0,This);
00472 
00473     return S_OK;
00474 }
00475 
00476 /******************************************************************************
00477  *                  FileMoniker_BindToObject
00478  */
00479 static HRESULT WINAPI
00480 FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
00481                              REFIID riid, VOID** ppvResult)
00482 {
00483     FileMonikerImpl *This = impl_from_IMoniker(iface);
00484     HRESULT   res=E_FAIL;
00485     CLSID     clsID;
00486     IUnknown* pObj=0;
00487     IRunningObjectTable *prot=0;
00488     IPersistFile  *ppf=0;
00489     IClassFactory *pcf=0;
00490     IClassActivator *pca=0;
00491 
00492     *ppvResult=0;
00493 
00494     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
00495 
00496     if(pmkToLeft==NULL){
00497 
00498         res=IBindCtx_GetRunningObjectTable(pbc,&prot);
00499 
00500         if (SUCCEEDED(res)){
00501             /* if the requested class was loaded before ! we don't need to reload it */
00502             res = IRunningObjectTable_GetObject(prot,iface,&pObj);
00503 
00504             if (res==S_FALSE){
00505                 /* first activation of this class */
00506                 res=GetClassFile(This->filePathName,&clsID);
00507                 if (SUCCEEDED(res)){
00508 
00509                     res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IPersistFile,(void**)&ppf);
00510                     if (SUCCEEDED(res)){
00511 
00512                         res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
00513                         if (SUCCEEDED(res)){
00514 
00515                             pObj=(IUnknown*)ppf;
00516                             IUnknown_AddRef(pObj);
00517                         }
00518                     }
00519                 }
00520             }
00521         }
00522     }
00523     else{
00524         res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf);
00525 
00526         if (res==E_NOINTERFACE){
00527 
00528             res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
00529 
00530             if (res==E_NOINTERFACE)
00531                 return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
00532         }
00533         if (pcf!=NULL){
00534 
00535             IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)&ppf);
00536 
00537             res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
00538 
00539             if (SUCCEEDED(res)){
00540 
00541                 pObj=(IUnknown*)ppf;
00542                 IUnknown_AddRef(pObj);
00543             }
00544         }
00545         if (pca!=NULL){
00546 
00547             FIXME("()\n");
00548 
00549             /*res=GetClassFile(This->filePathName,&clsID);
00550 
00551             if (SUCCEEDED(res)){
00552 
00553                 res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf);
00554 
00555                 if (SUCCEEDED(res)){
00556 
00557                     pObj=(IUnknown*)ppf;
00558                     IUnknown_AddRef(pObj);
00559                 }
00560             }*/
00561         }
00562     }
00563 
00564     if (pObj!=NULL){
00565         /* get the requested interface from the loaded class */
00566         res= IUnknown_QueryInterface(pObj,riid,ppvResult);
00567 
00568         IBindCtx_RegisterObjectBound(pbc,*ppvResult);
00569 
00570         IUnknown_Release(pObj);
00571     }
00572 
00573     if (prot!=NULL)
00574         IRunningObjectTable_Release(prot);
00575 
00576     if (ppf!=NULL)
00577         IPersistFile_Release(ppf);
00578 
00579     if (pca!=NULL)
00580         IClassActivator_Release(pca);
00581 
00582     if (pcf!=NULL)
00583         IClassFactory_Release(pcf);
00584 
00585     return res;
00586 }
00587 
00588 /******************************************************************************
00589  *        FileMoniker_BindToStorage
00590  */
00591 static HRESULT WINAPI
00592 FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
00593                               REFIID riid, VOID** ppvObject)
00594 {
00595     LPOLESTR filePath=0;
00596     IStorage *pstg=0;
00597     HRESULT res;
00598 
00599     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
00600 
00601     if (pmkToLeft==NULL){
00602 
00603         if (IsEqualIID(&IID_IStorage, riid)){
00604 
00605             /* get the file name */
00606             IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath);
00607 
00608             /* verify if the file contains a storage object */
00609             res=StgIsStorageFile(filePath);
00610 
00611             if(res==S_OK){
00612 
00613                 res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
00614 
00615                 if (SUCCEEDED(res)){
00616 
00617                     *ppvObject=pstg;
00618 
00619                     IStorage_AddRef(pstg);
00620 
00621                     return res;
00622                 }
00623             }
00624             CoTaskMemFree(filePath);
00625         }
00626         else
00627             if ( (IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)) )
00628                 return E_FAIL;
00629             else
00630                 return E_NOINTERFACE;
00631     }
00632     else {
00633 
00634         FIXME("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
00635 
00636         return E_NOTIMPL;
00637     }
00638     return res;
00639 }
00640 
00641 /******************************************************************************
00642  *        FileMoniker_Reduce
00643  ******************************************************************************/
00644 static HRESULT WINAPI
00645 FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
00646                        IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
00647 {
00648     TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
00649 
00650     if (ppmkReduced==NULL)
00651         return E_POINTER;
00652 
00653     IMoniker_AddRef(iface);
00654 
00655     *ppmkReduced=iface;
00656 
00657     return MK_S_REDUCED_TO_SELF;
00658 }
00659 
00660 /******************************************************************************
00661  *        FileMoniker_ComposeWith
00662  */
00663 static HRESULT WINAPI
00664 FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
00665                             BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
00666 {
00667     HRESULT res;
00668     LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0;
00669     static const WCHAR twoPoint[]={'.','.',0};
00670     static const WCHAR bkSlash[]={'\\',0};
00671     IBindCtx *bind=0;
00672     int i=0,j=0,lastIdx1=0,lastIdx2=0;
00673     DWORD mkSys;
00674 
00675     TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
00676 
00677     if (ppmkComposite==NULL)
00678         return E_POINTER;
00679 
00680     if (pmkRight==NULL)
00681     return E_INVALIDARG;
00682 
00683     *ppmkComposite=0;
00684 
00685     IMoniker_IsSystemMoniker(pmkRight,&mkSys);
00686 
00687     /* check if we have two FileMonikers to compose or not */
00688     if(mkSys==MKSYS_FILEMONIKER){
00689 
00690         CreateBindCtx(0,&bind);
00691 
00692         IMoniker_GetDisplayName(iface,bind,NULL,&str1);
00693         IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2);
00694 
00695         /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */
00696         lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1;
00697         lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1;
00698 
00699         if ((lastIdx1==-1 && lastIdx2>-1)||(lastIdx1==1 && lstrcmpW(strDec1[0],twoPoint)==0))
00700             return MK_E_SYNTAX;
00701 
00702         if(lstrcmpW(strDec1[lastIdx1],bkSlash)==0)
00703             lastIdx1--;
00704 
00705         /* for etch "..\" in the left of str2 remove the right element from str1 */
00706         for(i=0; ( (lastIdx1>=0) && (strDec2[i]!=NULL) && (lstrcmpW(strDec2[i],twoPoint)==0) ) ;i+=2){
00707 
00708             lastIdx1-=2;
00709         }
00710 
00711         /* the length of the composed path string  is raised by the sum of the two paths lengths  */
00712         newStr=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1));
00713 
00714       if (newStr==NULL)
00715         return E_OUTOFMEMORY;
00716 
00717         /* new path is the concatenation of the rest of str1 and str2 */
00718         for(*newStr=0,j=0;j<=lastIdx1;j++)
00719             strcatW(newStr,strDec1[j]);
00720 
00721         if ((strDec2[i]==NULL && lastIdx1>-1 && lastIdx2>-1) || lstrcmpW(strDec2[i],bkSlash)!=0)
00722             strcatW(newStr,bkSlash);
00723 
00724         for(j=i;j<=lastIdx2;j++)
00725             strcatW(newStr,strDec2[j]);
00726 
00727         /* create a new moniker with the new string */
00728         res=CreateFileMoniker(newStr,ppmkComposite);
00729 
00730         /* free all strings space memory used by this function */
00731         HeapFree(GetProcessHeap(),0,newStr);
00732 
00733         for(i=0; strDec1[i]!=NULL;i++)
00734             CoTaskMemFree(strDec1[i]);
00735         for(i=0; strDec2[i]!=NULL;i++)
00736             CoTaskMemFree(strDec2[i]);
00737         CoTaskMemFree(strDec1);
00738         CoTaskMemFree(strDec2);
00739 
00740         CoTaskMemFree(str1);
00741         CoTaskMemFree(str2);
00742 
00743         return res;
00744     }
00745     else if(mkSys==MKSYS_ANTIMONIKER){
00746 
00747         *ppmkComposite=NULL;
00748         return S_OK;
00749     }
00750     else if (fOnlyIfNotGeneric){
00751 
00752         *ppmkComposite=NULL;
00753         return MK_E_NEEDGENERIC;
00754     }
00755     else
00756 
00757         return CreateGenericComposite(iface,pmkRight,ppmkComposite);
00758 }
00759 
00760 /******************************************************************************
00761  *        FileMoniker_Enum
00762  */
00763 static HRESULT WINAPI
00764 FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
00765 {
00766     TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
00767 
00768     if (ppenumMoniker == NULL)
00769         return E_POINTER;
00770 
00771     *ppenumMoniker = NULL;
00772 
00773     return S_OK;
00774 }
00775 
00776 /******************************************************************************
00777  *        FileMoniker_IsEqual
00778  */
00779 static HRESULT WINAPI
00780 FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
00781 {
00782     FileMonikerImpl *This = impl_from_IMoniker(iface);
00783     CLSID clsid;
00784     LPOLESTR filePath;
00785     IBindCtx* bind;
00786     HRESULT res;
00787 
00788     TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
00789 
00790     if (pmkOtherMoniker==NULL)
00791         return S_FALSE;
00792 
00793     IMoniker_GetClassID(pmkOtherMoniker,&clsid);
00794 
00795     if (!IsEqualCLSID(&clsid,&CLSID_FileMoniker))
00796         return S_FALSE;
00797 
00798     res = CreateBindCtx(0,&bind);
00799     if (FAILED(res)) return res;
00800 
00801     res = S_FALSE;
00802     if (SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath))) {
00803     if (!lstrcmpiW(filePath, This->filePathName))
00804             res = S_OK;
00805     CoTaskMemFree(filePath);
00806     }
00807 
00808     IBindCtx_Release(bind);
00809     return res;
00810 }
00811 
00812 /******************************************************************************
00813  *        FileMoniker_Hash
00814  */
00815 static HRESULT WINAPI
00816 FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
00817 {
00818     FileMonikerImpl *This = impl_from_IMoniker(iface);
00819     int  h = 0,i,skip,len;
00820     int  off = 0;
00821     LPOLESTR val;
00822 
00823     if (pdwHash==NULL)
00824         return E_POINTER;
00825 
00826     val =  This->filePathName;
00827     len = lstrlenW(val);
00828 
00829     if (len < 16) {
00830         for (i = len ; i > 0; i--) {
00831             h = (h * 37) + val[off++];
00832     }
00833     } else {
00834         /* only sample some characters */
00835     skip = len / 8;
00836     for (i = len ; i > 0; i -= skip, off += skip) {
00837             h = (h * 39) + val[off];
00838     }
00839     }
00840 
00841     *pdwHash=h;
00842 
00843     return S_OK;
00844 }
00845 
00846 /******************************************************************************
00847  *        FileMoniker_IsRunning
00848  */
00849 static HRESULT WINAPI
00850 FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
00851                           IMoniker* pmkNewlyRunning)
00852 {
00853     IRunningObjectTable* rot;
00854     HRESULT res;
00855 
00856     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
00857 
00858     if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) )
00859         return S_OK;
00860 
00861     if (pbc==NULL)
00862         return E_POINTER;
00863 
00864     res=IBindCtx_GetRunningObjectTable(pbc,&rot);
00865 
00866     if (FAILED(res))
00867         return res;
00868 
00869     res = IRunningObjectTable_IsRunning(rot,iface);
00870 
00871     IRunningObjectTable_Release(rot);
00872 
00873     return res;
00874 }
00875 
00876 /******************************************************************************
00877  *        FileMoniker_GetTimeOfLastChange
00878  ******************************************************************************/
00879 static HRESULT WINAPI
00880 FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
00881                                     IMoniker* pmkToLeft, FILETIME* pFileTime)
00882 {
00883     FileMonikerImpl *This = impl_from_IMoniker(iface);
00884     IRunningObjectTable* rot;
00885     HRESULT res;
00886     WIN32_FILE_ATTRIBUTE_DATA info;
00887 
00888     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime);
00889 
00890     if (pFileTime==NULL)
00891         return E_POINTER;
00892 
00893     if (pmkToLeft!=NULL)
00894         return E_INVALIDARG;
00895 
00896     res=IBindCtx_GetRunningObjectTable(pbc,&rot);
00897 
00898     if (FAILED(res))
00899         return res;
00900 
00901     res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime);
00902 
00903     if (FAILED(res)){ /* the moniker is not registered */
00904 
00905         if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info))
00906             return MK_E_NOOBJECT;
00907 
00908         *pFileTime=info.ftLastWriteTime;
00909     }
00910 
00911     return S_OK;
00912 }
00913 
00914 /******************************************************************************
00915  *        FileMoniker_Inverse
00916  */
00917 static HRESULT WINAPI
00918 FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
00919 {
00920     TRACE("(%p,%p)\n",iface,ppmk);
00921 
00922     return CreateAntiMoniker(ppmk);
00923 }
00924 
00925 /******************************************************************************
00926  *        FileMoniker_CommonPrefixWith
00927  */
00928 static HRESULT WINAPI
00929 FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
00930 {
00931 
00932     LPOLESTR pathThis,pathOther,*stringTable1,*stringTable2,commonPath;
00933     IBindCtx *pbind;
00934     DWORD mkSys;
00935     ULONG nb1,nb2,i,sameIdx;
00936     BOOL machimeNameCase=FALSE;
00937 
00938     if (ppmkPrefix==NULL)
00939         return E_POINTER;
00940 
00941     if (pmkOther==NULL)
00942         return E_INVALIDARG;
00943 
00944     *ppmkPrefix=0;
00945 
00946     /* check if we have the same type of moniker */
00947     IMoniker_IsSystemMoniker(pmkOther,&mkSys);
00948 
00949     if(mkSys==MKSYS_FILEMONIKER){
00950         HRESULT ret;
00951 
00952         ret = CreateBindCtx(0,&pbind);
00953         if (FAILED(ret))
00954             return ret;
00955 
00956         /* create a string based on common part of the two paths */
00957 
00958         ret = IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis);
00959         if (FAILED(ret))
00960             return ret;
00961         ret = IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther);
00962         if (FAILED(ret))
00963             return ret;
00964 
00965         nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1);
00966         if (FAILED(nb1))
00967             return nb1;
00968         nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2);
00969         if (FAILED(nb2))
00970             return nb2;
00971 
00972         if (nb1==0 || nb2==0)
00973             return MK_E_NOPREFIX;
00974 
00975         commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1));
00976         if (!commonPath)
00977             return E_OUTOFMEMORY;
00978 
00979         *commonPath=0;
00980 
00981         for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) &&
00982                          (stringTable2[sameIdx]!=NULL) &&
00983                          (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++);
00984 
00985         if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){
00986 
00987             machimeNameCase=TRUE;
00988 
00989             for(i=2;i<sameIdx;i++)
00990 
00991                 if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){
00992                     machimeNameCase=FALSE;
00993                     break;
00994             }
00995         }
00996 
00997         if (machimeNameCase && *stringTable1[sameIdx-1]=='\\')
00998             sameIdx--;
00999 
01000         if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
01001             ret = MK_E_NOPREFIX;
01002         else
01003         {
01004             for(i=0;i<sameIdx;i++)
01005                 strcatW(commonPath,stringTable1[i]);
01006     
01007             for(i=0;i<nb1;i++)
01008                 CoTaskMemFree(stringTable1[i]);
01009     
01010             CoTaskMemFree(stringTable1);
01011     
01012             for(i=0;i<nb2;i++)
01013                 CoTaskMemFree(stringTable2[i]);
01014     
01015             CoTaskMemFree(stringTable2);
01016     
01017             ret = CreateFileMoniker(commonPath,ppmkPrefix);
01018         }
01019         HeapFree(GetProcessHeap(),0,commonPath);
01020         return ret;
01021     }
01022     else
01023         return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
01024 }
01025 
01026 /******************************************************************************
01027  *        DecomposePath (local function)
01028  */
01029 int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable)
01030 {
01031     static const WCHAR bSlash[] = {'\\',0};
01032     LPOLESTR word;
01033     int i=0,j,tabIndex=0, ret=0;
01034     LPOLESTR *strgtable ;
01035 
01036     int len=lstrlenW(str);
01037 
01038     TRACE("%s, %p\n", debugstr_w(str), *stringTable);
01039 
01040     strgtable = CoTaskMemAlloc((len + 1)*sizeof(*strgtable));
01041 
01042     if (strgtable==NULL)
01043     return E_OUTOFMEMORY;
01044 
01045     word = CoTaskMemAlloc((len + 1)*sizeof(WCHAR));
01046 
01047     if (word==NULL)
01048     {
01049         ret = E_OUTOFMEMORY;
01050         goto lend;
01051     }
01052 
01053     while(str[i]!=0){
01054 
01055         if(str[i]==bSlash[0]){
01056 
01057             strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR));
01058 
01059             if (strgtable[tabIndex]==NULL)
01060             {
01061                 ret = E_OUTOFMEMORY;
01062                 goto lend;
01063             }
01064 
01065             strcpyW(strgtable[tabIndex++],bSlash);
01066 
01067             i++;
01068 
01069         }
01070         else {
01071 
01072             for(j=0; str[i]!=0 && str[i]!=bSlash[0] ; i++,j++)
01073                 word[j]=str[i];
01074 
01075             word[j]=0;
01076 
01077             strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1));
01078 
01079             if (strgtable[tabIndex]==NULL)
01080             {
01081                 ret = E_OUTOFMEMORY;
01082                 goto lend;
01083             }
01084 
01085             strcpyW(strgtable[tabIndex++],word);
01086         }
01087     }
01088     strgtable[tabIndex]=NULL;
01089 
01090     *stringTable=strgtable;
01091 
01092     ret = tabIndex;
01093 
01094 lend:
01095     if (ret < 0)
01096     {
01097         for (i = 0; i < tabIndex; i++)
01098             CoTaskMemFree(strgtable[i]);
01099 
01100         CoTaskMemFree(strgtable);
01101     }
01102 
01103     if (word)
01104         CoTaskMemFree(word);
01105 
01106     return ret;
01107 }
01108 
01109 /******************************************************************************
01110  *        FileMoniker_RelativePathTo
01111  */
01112 static HRESULT WINAPI
01113 FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
01114 {
01115     IBindCtx *bind;
01116     HRESULT res;
01117     LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
01118     DWORD len1=0,len2=0,sameIdx=0,j=0;
01119     static const WCHAR back[] ={'.','.','\\',0};
01120 
01121     TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
01122 
01123     if (ppmkRelPath==NULL)
01124         return E_POINTER;
01125 
01126     if (pmOther==NULL)
01127         return E_INVALIDARG;
01128 
01129     res=CreateBindCtx(0,&bind);
01130     if (FAILED(res))
01131     return res;
01132 
01133     res=IMoniker_GetDisplayName(iface,bind,NULL,&str1);
01134     if (FAILED(res))
01135     return res;
01136     res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2);
01137     if (FAILED(res))
01138     return res;
01139 
01140     len1=FileMonikerImpl_DecomposePath(str1,&tabStr1);
01141     len2=FileMonikerImpl_DecomposePath(str2,&tabStr2);
01142 
01143     if (FAILED(len1) || FAILED(len2))
01144     return E_OUTOFMEMORY;
01145 
01146     /* count the number of similar items from the begin of the two paths */
01147     for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) &&
01148            (tabStr2[sameIdx]!=NULL) &&
01149                (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++);
01150 
01151     /* begin the construction of relativePath */
01152     /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */
01153     /* by "..\\" in the begin */
01154     relPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2)));
01155 
01156     *relPath=0;
01157 
01158     if (len2>0 && !(len1==1 && len2==1 && sameIdx==0))
01159         for(j=sameIdx;(tabStr1[j] != NULL); j++)
01160             if (*tabStr1[j]!='\\')
01161                 strcatW(relPath,back);
01162 
01163     /* add items of the second path (similar items with the first path are not included) to the relativePath */
01164     for(j=sameIdx;tabStr2[j]!=NULL;j++)
01165         strcatW(relPath,tabStr2[j]);
01166 
01167     res=CreateFileMoniker(relPath,ppmkRelPath);
01168 
01169     for(j=0; tabStr1[j]!=NULL;j++)
01170         CoTaskMemFree(tabStr1[j]);
01171     for(j=0; tabStr2[j]!=NULL;j++)
01172         CoTaskMemFree(tabStr2[j]);
01173     CoTaskMemFree(tabStr1);
01174     CoTaskMemFree(tabStr2);
01175     CoTaskMemFree(str1);
01176     CoTaskMemFree(str2);
01177     HeapFree(GetProcessHeap(),0,relPath);
01178 
01179     if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0))
01180         return MK_S_HIM;
01181 
01182     return res;
01183 }
01184 
01185 /******************************************************************************
01186  *        FileMoniker_GetDisplayName
01187  */
01188 static HRESULT WINAPI
01189 FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
01190                                IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
01191 {
01192     FileMonikerImpl *This = impl_from_IMoniker(iface);
01193     int len=lstrlenW(This->filePathName);
01194 
01195     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
01196 
01197     if (ppszDisplayName==NULL)
01198         return E_POINTER;
01199 
01200     if (pmkToLeft!=NULL)
01201         return E_INVALIDARG;
01202 
01203     *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
01204     if (*ppszDisplayName==NULL)
01205         return E_OUTOFMEMORY;
01206 
01207     strcpyW(*ppszDisplayName,This->filePathName);
01208 
01209     TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
01210     
01211     return S_OK;
01212 }
01213 
01214 /******************************************************************************
01215  *        FileMoniker_ParseDisplayName
01216  */
01217 static HRESULT WINAPI
01218 FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
01219                      LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
01220 {
01221     FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
01222     return E_NOTIMPL;
01223 }
01224 
01225 /******************************************************************************
01226  *        FileMoniker_IsSystemMoniker
01227  */
01228 static HRESULT WINAPI
01229 FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
01230 {
01231     TRACE("(%p,%p)\n",iface,pwdMksys);
01232 
01233     if (!pwdMksys)
01234         return E_POINTER;
01235 
01236     (*pwdMksys)=MKSYS_FILEMONIKER;
01237 
01238     return S_OK;
01239 }
01240 
01241 /*******************************************************************************
01242  *        FileMonikerIROTData_QueryInterface
01243  */
01244 static HRESULT WINAPI
01245 FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
01246 {
01247 
01248     FileMonikerImpl *This = impl_from_IROTData(iface);
01249 
01250     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
01251 
01252     return FileMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
01253 }
01254 
01255 /***********************************************************************
01256  *        FileMonikerIROTData_AddRef
01257  */
01258 static ULONG WINAPI
01259 FileMonikerROTDataImpl_AddRef(IROTData *iface)
01260 {
01261     FileMonikerImpl *This = impl_from_IROTData(iface);
01262 
01263     TRACE("(%p)\n",This);
01264 
01265     return IMoniker_AddRef(&This->IMoniker_iface);
01266 }
01267 
01268 /***********************************************************************
01269  *        FileMonikerIROTData_Release
01270  */
01271 static ULONG WINAPI
01272 FileMonikerROTDataImpl_Release(IROTData* iface)
01273 {
01274     FileMonikerImpl *This = impl_from_IROTData(iface);
01275 
01276     TRACE("(%p)\n",This);
01277 
01278     return FileMonikerImpl_Release(&This->IMoniker_iface);
01279 }
01280 
01281 /******************************************************************************
01282  *        FileMonikerIROTData_GetComparisonData
01283  */
01284 static HRESULT WINAPI
01285 FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData,
01286                                           ULONG cbMax, ULONG* pcbData)
01287 {
01288     FileMonikerImpl *This = impl_from_IROTData(iface);
01289     int len = strlenW(This->filePathName)+1;
01290     int i;
01291     LPWSTR pszFileName;
01292 
01293     TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
01294 
01295     *pcbData = sizeof(CLSID) + len * sizeof(WCHAR);
01296     if (cbMax < *pcbData)
01297         return E_OUTOFMEMORY;
01298 
01299     memcpy(pbData, &CLSID_FileMoniker, sizeof(CLSID));
01300     pszFileName = (LPWSTR)(pbData+sizeof(CLSID));
01301     for (i = 0; i < len; i++)
01302         pszFileName[i] = toupperW(This->filePathName[i]);
01303 
01304     return S_OK;
01305 }
01306 
01307 /*
01308  * Virtual function table for the FileMonikerImpl class which include IPersist,
01309  * IPersistStream and IMoniker functions.
01310  */
01311 static const IMonikerVtbl VT_FileMonikerImpl =
01312 {
01313     FileMonikerImpl_QueryInterface,
01314     FileMonikerImpl_AddRef,
01315     FileMonikerImpl_Release,
01316     FileMonikerImpl_GetClassID,
01317     FileMonikerImpl_IsDirty,
01318     FileMonikerImpl_Load,
01319     FileMonikerImpl_Save,
01320     FileMonikerImpl_GetSizeMax,
01321     FileMonikerImpl_BindToObject,
01322     FileMonikerImpl_BindToStorage,
01323     FileMonikerImpl_Reduce,
01324     FileMonikerImpl_ComposeWith,
01325     FileMonikerImpl_Enum,
01326     FileMonikerImpl_IsEqual,
01327     FileMonikerImpl_Hash,
01328     FileMonikerImpl_IsRunning,
01329     FileMonikerImpl_GetTimeOfLastChange,
01330     FileMonikerImpl_Inverse,
01331     FileMonikerImpl_CommonPrefixWith,
01332     FileMonikerImpl_RelativePathTo,
01333     FileMonikerImpl_GetDisplayName,
01334     FileMonikerImpl_ParseDisplayName,
01335     FileMonikerImpl_IsSystemMoniker
01336 };
01337 
01338 /* Virtual function table for the IROTData class. */
01339 static const IROTDataVtbl VT_ROTDataImpl =
01340 {
01341     FileMonikerROTDataImpl_QueryInterface,
01342     FileMonikerROTDataImpl_AddRef,
01343     FileMonikerROTDataImpl_Release,
01344     FileMonikerROTDataImpl_GetComparisonData
01345 };
01346 
01347 /******************************************************************************
01348  *         FileMoniker_Construct (local function)
01349  */
01350 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
01351 {
01352     int nb=0,i;
01353     int sizeStr=lstrlenW(lpszPathName);
01354     LPOLESTR *tabStr=0;
01355     static const WCHAR twoPoint[]={'.','.',0};
01356     static const WCHAR bkSlash[]={'\\',0};
01357     BYTE addBkSlash;
01358 
01359     TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName));
01360 
01361     /* Initialize the virtual function table. */
01362     This->IMoniker_iface.lpVtbl = &VT_FileMonikerImpl;
01363     This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
01364     This->ref          = 0;
01365     This->pMarshal     = NULL;
01366 
01367     This->filePathName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1));
01368 
01369     if (This->filePathName==NULL)
01370         return E_OUTOFMEMORY;
01371 
01372     strcpyW(This->filePathName,lpszPathName);
01373 
01374     nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr);
01375 
01376     if (nb > 0 ){
01377 
01378         addBkSlash=1;
01379         if (lstrcmpW(tabStr[0],twoPoint)!=0)
01380             addBkSlash=0;
01381         else
01382             for(i=0;i<nb;i++){
01383 
01384                 if ( (lstrcmpW(tabStr[i],twoPoint)!=0) && (lstrcmpW(tabStr[i],bkSlash)!=0) ){
01385                     addBkSlash=0;
01386                     break;
01387                 }
01388                 else
01389 
01390                     if (lstrcmpW(tabStr[i],bkSlash)==0 && i<nb-1 && lstrcmpW(tabStr[i+1],bkSlash)==0){
01391                         *tabStr[i]=0;
01392                         sizeStr--;
01393                         addBkSlash=0;
01394                         break;
01395                     }
01396             }
01397 
01398         if (lstrcmpW(tabStr[nb-1],bkSlash)==0)
01399             addBkSlash=0;
01400 
01401         This->filePathName=HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR));
01402 
01403         *This->filePathName=0;
01404 
01405         for(i=0;tabStr[i]!=NULL;i++)
01406             strcatW(This->filePathName,tabStr[i]);
01407 
01408         if (addBkSlash)
01409             strcatW(This->filePathName,bkSlash);
01410     }
01411 
01412     for(i=0; tabStr[i]!=NULL;i++)
01413         CoTaskMemFree(tabStr[i]);
01414     CoTaskMemFree(tabStr);
01415 
01416     return S_OK;
01417 }
01418 
01419 /******************************************************************************
01420  *        CreateFileMoniker (OLE32.@)
01421  ******************************************************************************/
01422 HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, IMoniker **ppmk)
01423 {
01424     FileMonikerImpl* newFileMoniker;
01425     HRESULT  hr;
01426 
01427     TRACE("(%s,%p)\n",debugstr_w(lpszPathName),ppmk);
01428 
01429     if (!ppmk)
01430         return E_POINTER;
01431 
01432     if(!lpszPathName)
01433         return MK_E_SYNTAX;
01434 
01435     *ppmk=NULL;
01436 
01437     newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
01438 
01439     if (!newFileMoniker)
01440         return E_OUTOFMEMORY;
01441 
01442     hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName);
01443 
01444     if (SUCCEEDED(hr))
01445         hr = IMoniker_QueryInterface(&newFileMoniker->IMoniker_iface,&IID_IMoniker,(void**)ppmk);
01446     else
01447         HeapFree(GetProcessHeap(),0,newFileMoniker);
01448 
01449     return hr;
01450 }
01451 
01452 /* find a character from a set in reverse without the string having to be null-terminated */
01453 static inline WCHAR *memrpbrkW(const WCHAR *ptr, size_t n, const WCHAR *accept)
01454 {
01455     const WCHAR *end, *ret = NULL;
01456     for (end = ptr + n; ptr < end; ptr++) if (strchrW(accept, *ptr)) ret = ptr;
01457     return (WCHAR *)ret;
01458 }
01459 
01460 HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
01461                                           LPDWORD pchEaten, IMoniker **ppmk)
01462 {
01463     LPCWSTR end;
01464     static const WCHAR wszSeparators[] = {':','\\','/','!',0};
01465 
01466     for (end = szDisplayName + strlenW(szDisplayName);
01467          end && (end != szDisplayName);
01468          end = memrpbrkW(szDisplayName, end - szDisplayName, wszSeparators))
01469     {
01470         HRESULT hr;
01471         IRunningObjectTable *rot;
01472         IMoniker *file_moniker;
01473         LPWSTR file_display_name;
01474         LPWSTR full_path_name;
01475         DWORD full_path_name_len;
01476         int len = end - szDisplayName;
01477 
01478         file_display_name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
01479         if (!file_display_name) return E_OUTOFMEMORY;
01480         memcpy(file_display_name, szDisplayName, len * sizeof(WCHAR));
01481         file_display_name[len] = '\0';
01482 
01483         hr = CreateFileMoniker(file_display_name, &file_moniker);
01484         if (FAILED(hr))
01485         {
01486             HeapFree(GetProcessHeap(), 0, file_display_name);
01487             return hr;
01488         }
01489 
01490         hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
01491         if (FAILED(hr))
01492         {
01493             HeapFree(GetProcessHeap(), 0, file_display_name);
01494             IMoniker_Release(file_moniker);
01495             return hr;
01496         }
01497 
01498         hr = IRunningObjectTable_IsRunning(rot, file_moniker);
01499         IRunningObjectTable_Release(rot);
01500         if (FAILED(hr))
01501         {
01502             HeapFree(GetProcessHeap(), 0, file_display_name);
01503             IMoniker_Release(file_moniker);
01504             return hr;
01505         }
01506         if (hr == S_OK)
01507         {
01508             TRACE("found running file moniker for %s\n", debugstr_w(file_display_name));
01509             *pchEaten = len;
01510             *ppmk = file_moniker;
01511             HeapFree(GetProcessHeap(), 0, file_display_name);
01512             return S_OK;
01513         }
01514 
01515         full_path_name_len = GetFullPathNameW(file_display_name, 0, NULL, NULL);
01516         if (!full_path_name_len)
01517         {
01518             HeapFree(GetProcessHeap(), 0, file_display_name);
01519             IMoniker_Release(file_moniker);
01520             return MK_E_SYNTAX;
01521         }
01522         full_path_name = HeapAlloc(GetProcessHeap(), 0, full_path_name_len * sizeof(WCHAR));
01523         if (!full_path_name)
01524         {
01525             HeapFree(GetProcessHeap(), 0, file_display_name);
01526             IMoniker_Release(file_moniker);
01527             return E_OUTOFMEMORY;
01528         }
01529         GetFullPathNameW(file_display_name, full_path_name_len, full_path_name, NULL);
01530 
01531         if (GetFileAttributesW(full_path_name) == INVALID_FILE_ATTRIBUTES)
01532             TRACE("couldn't open file %s\n", debugstr_w(full_path_name));
01533         else
01534         {
01535             TRACE("got file moniker for %s\n", debugstr_w(szDisplayName));
01536             *pchEaten = len;
01537             *ppmk = file_moniker;
01538             HeapFree(GetProcessHeap(), 0, file_display_name);
01539             HeapFree(GetProcessHeap(), 0, full_path_name);
01540             return S_OK;
01541         }
01542         HeapFree(GetProcessHeap(), 0, file_display_name);
01543         HeapFree(GetProcessHeap(), 0, full_path_name);
01544         IMoniker_Release(file_moniker);
01545     }
01546 
01547     return MK_E_CANTOPENFILE;
01548 }
01549 
01550 
01551 static HRESULT WINAPI FileMonikerCF_QueryInterface(LPCLASSFACTORY iface,
01552                                                   REFIID riid, LPVOID *ppv)
01553 {
01554     *ppv = NULL;
01555     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
01556     {
01557         *ppv = iface;
01558         IUnknown_AddRef(iface);
01559         return S_OK;
01560     }
01561     return E_NOINTERFACE;
01562 }
01563 
01564 static ULONG WINAPI FileMonikerCF_AddRef(LPCLASSFACTORY iface)
01565 {
01566     return 2; /* non-heap based object */
01567 }
01568 
01569 static ULONG WINAPI FileMonikerCF_Release(LPCLASSFACTORY iface)
01570 {
01571     return 1; /* non-heap based object */
01572 }
01573 
01574 static HRESULT WINAPI FileMonikerCF_CreateInstance(LPCLASSFACTORY iface,
01575     LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
01576 {
01577     FileMonikerImpl* newFileMoniker;
01578     HRESULT  hr;
01579     static const WCHAR wszEmpty[] = { 0 };
01580 
01581     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
01582 
01583     *ppv = NULL;
01584 
01585     if (pUnk)
01586         return CLASS_E_NOAGGREGATION;
01587 
01588     newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
01589     if (!newFileMoniker)
01590         return E_OUTOFMEMORY;
01591 
01592     hr = FileMonikerImpl_Construct(newFileMoniker, wszEmpty);
01593 
01594     if (SUCCEEDED(hr))
01595         hr = IMoniker_QueryInterface(&newFileMoniker->IMoniker_iface, riid, ppv);
01596     if (FAILED(hr))
01597         HeapFree(GetProcessHeap(),0,newFileMoniker);
01598 
01599     return hr;
01600 }
01601 
01602 static HRESULT WINAPI FileMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
01603 {
01604     FIXME("(%d), stub!\n",fLock);
01605     return S_OK;
01606 }
01607 
01608 static const IClassFactoryVtbl FileMonikerCFVtbl =
01609 {
01610     FileMonikerCF_QueryInterface,
01611     FileMonikerCF_AddRef,
01612     FileMonikerCF_Release,
01613     FileMonikerCF_CreateInstance,
01614     FileMonikerCF_LockServer
01615 };
01616 static const IClassFactoryVtbl *FileMonikerCF = &FileMonikerCFVtbl;
01617 
01618 HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv)
01619 {
01620     return IClassFactory_QueryInterface((IClassFactory *)&FileMonikerCF, riid, ppv);
01621 }

Generated on Sat May 26 2012 04:24:09 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.