filemoniker.c 44.1 KB
Newer Older
1 2
/*
 * FileMonikers implementation
3
 *
4
 * Copyright 1999  Noomen Hamza
5
 * Copyright 2007  Robert Shearman
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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>
Andreas Mohr's avatar
Andreas Mohr committed
24
#include <string.h>
25

26
#define COBJMACROS
27 28
#define NONAMELESSUNION
#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"
Noomen Hamza's avatar
Noomen Hamza committed
36
#include "objbase.h"
37
#include "moniker.h"
Noomen Hamza's avatar
Noomen Hamza committed
38

39 40
#include "compobj_private.h"

41
WINE_DEFAULT_DEBUG_CHANNEL(ole);
42

Noomen Hamza's avatar
Noomen Hamza committed
43
/* filemoniker data structure */
44 45
typedef struct FileMonikerImpl{

46
    const IMonikerVtbl*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/
Noomen Hamza's avatar
Noomen Hamza committed
47

48
    /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether
Noomen Hamza's avatar
Noomen Hamza committed
49 50
     * two monikers are equal. That's whay IROTData interface is implemented by monikers.
     */
51
    const IROTDataVtbl*  lpvtbl2;  /* VTable relative to the IROTData interface.*/
Noomen Hamza's avatar
Noomen Hamza committed
52

53
    LONG ref; /* reference counter for this object */
54

Noomen Hamza's avatar
Noomen Hamza committed
55
    LPOLESTR filePathName; /* path string identified by this filemoniker */
56

57
    IUnknown *pMarshal; /* custom marshaler */
58 59
} FileMonikerImpl;

60 61 62 63 64
static inline IMoniker *impl_from_IROTData( IROTData *iface )
{
    return (IMoniker *)((char*)iface - FIELD_OFFSET(FileMonikerImpl, lpvtbl2));
}

Noomen Hamza's avatar
Noomen Hamza committed
65
/* Local function used by filemoniker implementation */
66 67
static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
static HRESULT FileMonikerImpl_Destroy(FileMonikerImpl* iface);
Noomen Hamza's avatar
Noomen Hamza committed
68

69 70
/*******************************************************************************
 *        FileMoniker_QueryInterface
71 72 73
 */
static HRESULT WINAPI
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

Noomen Hamza's avatar
Noomen Hamza committed
79 80 81
    /* Perform a sanity check on the parameters.*/
    if ( (This==0) || (ppvObject==0) )
	return E_INVALIDARG;
82

Noomen Hamza's avatar
Noomen Hamza committed
83
    /* Initialize the return parameter */
84
    *ppvObject = 0;
85

Noomen Hamza's avatar
Noomen Hamza committed
86 87 88 89 90 91 92
    /* Compare the riid with the interface IDs implemented by this object.*/
    if (IsEqualIID(&IID_IUnknown, riid)      ||
        IsEqualIID(&IID_IPersist, riid)      ||
        IsEqualIID(&IID_IPersistStream,riid) ||
        IsEqualIID(&IID_IMoniker, riid)
       )
        *ppvObject = iface;
93

Noomen Hamza's avatar
Noomen Hamza committed
94 95
    else if (IsEqualIID(&IID_IROTData, riid))
        *ppvObject = (IROTData*)&(This->lpvtbl2);
96 97 98 99 100 101 102 103 104
    else if (IsEqualIID(&IID_IMarshal, riid))
    {
        HRESULT hr = S_OK;
        if (!This->pMarshal)
            hr = MonikerMarshal_Create(iface, &This->pMarshal);
        if (hr != S_OK)
            return hr;
        return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
    }
Noomen Hamza's avatar
Noomen Hamza committed
105 106 107 108

    /* Check that we obtained an interface.*/
    if ((*ppvObject)==0)
        return E_NOINTERFACE;
109

Noomen Hamza's avatar
Noomen Hamza committed
110
    /* Query Interface always increases the reference count by one when it is successful */
111
    IMoniker_AddRef(iface);
112

Noomen Hamza's avatar
Noomen Hamza committed
113
    return S_OK;
114 115 116 117
}

/******************************************************************************
 *        FileMoniker_AddRef
118 119 120
 */
static ULONG WINAPI
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 133
 */
static ULONG WINAPI
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

Noomen Hamza's avatar
Noomen Hamza committed
142
    /* destroy the object if there's no more reference on it */
143
    if (ref == 0) FileMonikerImpl_Destroy(This);
Noomen Hamza's avatar
Noomen Hamza committed
144

145
    return ref;
146 147 148 149
}

/******************************************************************************
 *        FileMoniker_GetClassID
150 151 152
 */
static HRESULT WINAPI
FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID)
153
{
Robert Shearman's avatar
Robert Shearman committed
154
    TRACE("(%p,%p)\n",iface,pClassID);
155

Noomen Hamza's avatar
Noomen Hamza committed
156 157
    if (pClassID==NULL)
        return E_POINTER;
158

Noomen Hamza's avatar
Noomen Hamza committed
159
    *pClassID = CLSID_FileMoniker;
160

Noomen Hamza's avatar
Noomen Hamza committed
161
    return S_OK;
162 163 164 165
}

/******************************************************************************
 *        FileMoniker_IsDirty
166 167 168 169 170 171 172
 *
 * Note that the OLE-provided implementations of the IPersistStream::IsDirty
 * method in the OLE-provided moniker interfaces always return S_FALSE because
 * their internal state never changes.
 */
static HRESULT WINAPI
FileMonikerImpl_IsDirty(IMoniker* iface)
173
{
174

175
    TRACE("(%p)\n",iface);
176

Noomen Hamza's avatar
Noomen Hamza committed
177
    return S_FALSE;
178 179 180 181
}

/******************************************************************************
 *        FileMoniker_Load
182 183 184 185 186
 *
 * this function locates and reads from the stream the filePath string
 * written by FileMonikerImpl_Save
 */
static HRESULT WINAPI
187
FileMonikerImpl_Load(IMoniker* iface, IStream* pStm)
188
{
Noomen Hamza's avatar
Noomen Hamza committed
189
    HRESULT res;
190 191
    CHAR* filePathA = NULL;
    WCHAR* filePathW = NULL;
Noomen Hamza's avatar
Noomen Hamza committed
192 193
    ULONG bread;
    WORD  wbuffer;
194 195
    DWORD dwbuffer, bytesA, bytesW, len;
    int i;
196

197
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
198

199
    TRACE("(%p,%p)\n",iface,pStm);
Noomen Hamza's avatar
Noomen Hamza committed
200

201
    /* first WORD must be 0 */
Noomen Hamza's avatar
Noomen Hamza committed
202 203
    res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
    if (bread!=sizeof(WORD) || wbuffer!=0)
204
    {
205 206
        WARN("Couldn't read 0 word\n");
        goto fail;
207
    }
208

Noomen Hamza's avatar
Noomen Hamza committed
209
    /* read filePath string length (plus one) */
210
    res=IStream_Read(pStm,&bytesA,sizeof(DWORD),&bread);
Noomen Hamza's avatar
Noomen Hamza committed
211
    if (bread != sizeof(DWORD))
212
    {
213 214
        WARN("Couldn't read file string length\n");
        goto fail;
215
    }
Noomen Hamza's avatar
Noomen Hamza committed
216 217

    /* read filePath string */
218 219 220 221 222 223 224 225 226
    filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
    if (!filePathA)
    {
        res = E_OUTOFMEMORY;
        goto fail;
    }

    res=IStream_Read(pStm,filePathA,bytesA,&bread);
    if (bread != bytesA)
227
    {
228 229
        WARN("Couldn't read file path string\n");
        goto fail;
230
    }
Noomen Hamza's avatar
Noomen Hamza committed
231 232 233 234

    /* read the first constant */
    IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
    if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF)
235
    {
236 237
        WARN("Couldn't read 0xDEADFFFF constant\n");
        goto fail;
238
    }
239

240 241 242 243
    for(i=0;i<5;i++)
    {
        res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
        if (bread!=sizeof(DWORD) || dwbuffer!=0)
244
        {
245 246
            WARN("Couldn't read 0 padding\n");
            goto fail;
247
        }
Noomen Hamza's avatar
Noomen Hamza committed
248
    }
249

Noomen Hamza's avatar
Noomen Hamza committed
250
    res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
    if (bread!=sizeof(DWORD))
        goto fail;

    if (!dwbuffer) /* No W-string */
    {        
        bytesA--;
        len=MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, bytesA, NULL, 0);
        if (!len)
            goto fail;

        filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
        if (!filePathW)
        {
            res = E_OUTOFMEMORY;
            goto fail;
        }
        MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, -1, filePathW, len+1);
        goto succeed;
    }
Noomen Hamza's avatar
Noomen Hamza committed
270

271 272 273 274
    if (dwbuffer < 6)
        goto fail;

    bytesW=dwbuffer - 6;
275

Noomen Hamza's avatar
Noomen Hamza committed
276
    res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
277 278
    if (bread!=sizeof(DWORD) || dwbuffer!=bytesW)
        goto fail;
Noomen Hamza's avatar
Noomen Hamza committed
279 280 281

    res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
    if (bread!=sizeof(WORD) || wbuffer!=0x3)
282 283 284 285 286 287 288 289
        goto fail;

    len=bytesW/sizeof(WCHAR);
    filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
    if(!filePathW)
    {
         res = E_OUTOFMEMORY;
         goto fail;
290
    }
291 292 293
    res=IStream_Read(pStm,filePathW,bytesW,&bread);
    if (bread!=bytesW)
         goto fail;
Noomen Hamza's avatar
Noomen Hamza committed
294

295
    filePathW[len]=0;
Noomen Hamza's avatar
Noomen Hamza committed
296

297 298 299
 succeed:
    HeapFree(GetProcessHeap(),0,filePathA);
    HeapFree(GetProcessHeap(),0,This->filePathName);
Noomen Hamza's avatar
Noomen Hamza committed
300 301
    This->filePathName=filePathW;

302 303 304 305 306 307 308 309
    return S_OK;

 fail:
    HeapFree(GetProcessHeap(), 0, filePathA);
    HeapFree(GetProcessHeap(), 0, filePathW);

    if (SUCCEEDED(res))
         res = E_FAIL;
Noomen Hamza's avatar
Noomen Hamza committed
310
    return res;
311 312 313
}

/******************************************************************************
314
 *        FileMoniker_Save
315
 *
316
 * This function saves data of this object. In the beginning I thought
317
 * that I have just to write the filePath string on Stream. But, when I
318
 * tested this function with windows program samples, I noticed that it
319 320 321 322
 * was not the case. This implementation is based on XP SP2. Other versions
 * of Windows have minor variations.
 *
 * Data which must be written on stream is:
323 324 325 326
 * 1) WORD constant:zero
 * 2) length of the path string ("\0" included)
 * 3) path string type A
 * 4) DWORD constant : 0xDEADFFFF
327 328 329 330
 * 5) five DWORD constant: zero
 * 6) If we're only writing the multibyte version, 
 *     write a zero DWORD and finish.
 *
331
 * 7) DWORD: double-length of the path string type W ("\0" not
332
 *    included)
333 334 335
 * 8) WORD constant: 0x3
 * 9) filePath unicode string.
 *
336 337 338
 */
static HRESULT WINAPI
FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
339
{
340
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
Noomen Hamza's avatar
Noomen Hamza committed
341 342 343

    HRESULT res;
    LPOLESTR filePathW=This->filePathName;
344 345
    CHAR*    filePathA;
    DWORD bytesA, bytesW, len;
Noomen Hamza's avatar
Noomen Hamza committed
346

347 348 349
    static const DWORD DEADFFFF = 0xDEADFFFF;  /* Constants */
    static const DWORD ZERO     = 0;
    static const WORD  THREE    = 0x3;
Noomen Hamza's avatar
Noomen Hamza committed
350

351 352
    int i;
    BOOL bUsedDefault, bWriteWide;
Noomen Hamza's avatar
Noomen Hamza committed
353

354
    TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
Noomen Hamza's avatar
Noomen Hamza committed
355 356 357 358

    if (pStm==NULL)
        return E_POINTER;

359 360
    /* write a 0 WORD */
    res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
361
    if (FAILED(res)) return res;
362 363 364 365

    /* write length of filePath string ( 0 included )*/
    bytesA = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
    res=IStream_Write(pStm,&bytesA,sizeof(DWORD),NULL);
366
    if (FAILED(res)) return res;
367 368 369 370 371 372 373

    /* write A string (with '\0') */
    filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
    if (!filePathA)
        return E_OUTOFMEMORY;
    WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, bytesA, NULL, &bUsedDefault);
    res=IStream_Write(pStm,filePathA,bytesA,NULL);
Noomen Hamza's avatar
Noomen Hamza committed
374
    HeapFree(GetProcessHeap(),0,filePathA);
375
    if (FAILED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
376

377 378
    /* write a DWORD 0xDEADFFFF */
    res=IStream_Write(pStm,&DEADFFFF,sizeof(DWORD),NULL);
379
    if (FAILED(res)) return res;
380

381 382 383 384
    /* write 5 zero DWORDs */
    for(i=0;i<5;i++)
    {
        res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
385
        if (FAILED(res)) return res;
386
    }
Noomen Hamza's avatar
Noomen Hamza committed
387

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    /* Write the wide version if:
     *    + couldn't convert to CP_ACP, 
     * or + it's a directory, 
     * or + there's a character > 0xFF 
     */
    len = lstrlenW(filePathW);
    bWriteWide = (bUsedDefault || (len > 0 && filePathW[len-1]=='\\' ));
    if (!bWriteWide)
    {
        WCHAR* pch;
        for(pch=filePathW;*pch;++pch) 
        {
            if (*pch > 0xFF)
            {
                bWriteWide = TRUE;
                break;
            }
        }
    }
Noomen Hamza's avatar
Noomen Hamza committed
407

408 409 410
    if (!bWriteWide)
    {
        res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
Noomen Hamza's avatar
Noomen Hamza committed
411
        return res;
412 413 414 415 416
    }

    /* write bytes needed for the filepathW (without 0) + 6 */
    bytesW = len*sizeof(WCHAR) + 6;
    res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
417
    if (FAILED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
418

419 420 421
    /* try again, without the extra 6 */
    bytesW -= 6;
    res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
422
    if (FAILED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
423

424 425
    /* write a WORD 3 */
    res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
426
    if (FAILED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
427

428 429
    /* write W string (no 0) */
    res=IStream_Write(pStm,filePathW,bytesW,NULL);
Noomen Hamza's avatar
Noomen Hamza committed
430 431

    return res;
432 433 434 435
}

/******************************************************************************
 *        FileMoniker_GetSizeMax
436 437 438
 */
static HRESULT WINAPI
FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
439
{
440
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
441

442
    TRACE("(%p,%p)\n",iface,pcbSize);
443

444
    if (!pcbSize)
Noomen Hamza's avatar
Noomen Hamza committed
445 446
        return E_POINTER;

447 448 449 450 451
    /* We could calculate exactly (see ...::Save()) but instead
     * we'll make a quick over-estimate, like Windows (NT4, XP) does.
     */
    pcbSize->u.LowPart  = 0x38 + 4 * lstrlenW(This->filePathName);
    pcbSize->u.HighPart = 0;
Noomen Hamza's avatar
Noomen Hamza committed
452 453

    return S_OK;
454 455 456
}

/******************************************************************************
Noomen Hamza's avatar
Noomen Hamza committed
457
 *        FileMoniker_Destroy (local function)
458
 *******************************************************************************/
459
HRESULT FileMonikerImpl_Destroy(FileMonikerImpl* This)
Noomen Hamza's avatar
Noomen Hamza committed
460
{
461
    TRACE("(%p)\n",This);
462

463
    if (This->pMarshal) IUnknown_Release(This->pMarshal);
464
    HeapFree(GetProcessHeap(),0,This->filePathName);
Noomen Hamza's avatar
Noomen Hamza committed
465
    HeapFree(GetProcessHeap(),0,This);
466 467 468 469 470 471

    return S_OK;
}

/******************************************************************************
 *                  FileMoniker_BindToObject
472 473 474 475
 */
static HRESULT WINAPI
FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                             REFIID riid, VOID** ppvResult)
476
{
Noomen Hamza's avatar
Noomen Hamza committed
477 478 479 480 481 482 483
    HRESULT   res=E_FAIL;
    CLSID     clsID;
    IUnknown* pObj=0;
    IRunningObjectTable *prot=0;
    IPersistFile  *ppf=0;
    IClassFactory *pcf=0;
    IClassActivator *pca=0;
484

485
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
486

Noomen Hamza's avatar
Noomen Hamza committed
487 488
    *ppvResult=0;

Robert Shearman's avatar
Robert Shearman committed
489
    TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
Noomen Hamza's avatar
Noomen Hamza committed
490 491

    if(pmkToLeft==NULL){
492

Noomen Hamza's avatar
Noomen Hamza committed
493 494 495
        res=IBindCtx_GetRunningObjectTable(pbc,&prot);

        if (SUCCEEDED(res)){
496
            /* if the requested class was loaded before ! we don't need to reload it */
Noomen Hamza's avatar
Noomen Hamza committed
497 498 499 500 501 502 503
            res = IRunningObjectTable_GetObject(prot,iface,&pObj);

            if (res==S_FALSE){
                /* first activation of this class */
                res=GetClassFile(This->filePathName,&clsID);
                if (SUCCEEDED(res)){

504
                    res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IPersistFile,(void**)&ppf);
Noomen Hamza's avatar
Noomen Hamza committed
505 506 507 508 509 510 511 512 513 514 515 516 517 518
                    if (SUCCEEDED(res)){

                        res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
                        if (SUCCEEDED(res)){

                            pObj=(IUnknown*)ppf;
                            IUnknown_AddRef(pObj);
                        }
                    }
                }
            }
        }
    }
    else{
519
        res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf);
Noomen Hamza's avatar
Noomen Hamza committed
520 521 522

        if (res==E_NOINTERFACE){

523
            res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
524

Noomen Hamza's avatar
Noomen Hamza committed
525 526 527 528 529
            if (res==E_NOINTERFACE)
                return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
        }
        if (pcf!=NULL){

530
            IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)&ppf);
Noomen Hamza's avatar
Noomen Hamza committed
531 532 533 534 535 536 537 538 539 540 541

            res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);

            if (SUCCEEDED(res)){

                pObj=(IUnknown*)ppf;
                IUnknown_AddRef(pObj);
            }
        }
        if (pca!=NULL){

542
            FIXME("()\n");
543

Noomen Hamza's avatar
Noomen Hamza committed
544 545 546 547 548 549 550 551 552 553 554 555 556
            /*res=GetClassFile(This->filePathName,&clsID);

            if (SUCCEEDED(res)){

                res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf);

                if (SUCCEEDED(res)){

                    pObj=(IUnknown*)ppf;
                    IUnknown_AddRef(pObj);
                }
            }*/
        }
557
    }
Noomen Hamza's avatar
Noomen Hamza committed
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578

    if (pObj!=NULL){
        /* get the requested interface from the loaded class */
        res= IUnknown_QueryInterface(pObj,riid,ppvResult);

        IBindCtx_RegisterObjectBound(pbc,(IUnknown*)*ppvResult);

        IUnknown_Release(pObj);
    }

    if (prot!=NULL)
        IRunningObjectTable_Release(prot);

    if (ppf!=NULL)
        IPersistFile_Release(ppf);

    if (pca!=NULL)
        IClassActivator_Release(pca);

    if (pcf!=NULL)
        IClassFactory_Release(pcf);
579

Noomen Hamza's avatar
Noomen Hamza committed
580
    return res;
581 582 583 584
}

/******************************************************************************
 *        FileMoniker_BindToStorage
585 586 587 588
 */
static HRESULT WINAPI
FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                              REFIID riid, VOID** ppvObject)
589
{
Noomen Hamza's avatar
Noomen Hamza committed
590 591 592 593
    LPOLESTR filePath=0;
    IStorage *pstg=0;
    HRESULT res;

Robert Shearman's avatar
Robert Shearman committed
594
    TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
Noomen Hamza's avatar
Noomen Hamza committed
595 596 597 598 599 600

    if (pmkToLeft==NULL){

        if (IsEqualIID(&IID_IStorage, riid)){

            /* get the file name */
601
            IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath);
Noomen Hamza's avatar
Noomen Hamza committed
602

Austin English's avatar
Austin English committed
603
            /* verify if the file contains a storage object */
Noomen Hamza's avatar
Noomen Hamza committed
604 605 606 607 608 609 610
            res=StgIsStorageFile(filePath);

            if(res==S_OK){

                res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg);

                if (SUCCEEDED(res)){
611

Noomen Hamza's avatar
Noomen Hamza committed
612 613 614 615 616 617 618 619 620 621 622
                    *ppvObject=pstg;

                    IStorage_AddRef(pstg);

                    return res;
                }
            }
            CoTaskMemFree(filePath);
        }
        else
            if ( (IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)) )
623
                return E_FAIL;
Noomen Hamza's avatar
Noomen Hamza committed
624 625 626 627 628
            else
                return E_NOINTERFACE;
    }
    else {

Robert Shearman's avatar
Robert Shearman committed
629
        FIXME("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
630

631 632
        return E_NOTIMPL;
    }
Noomen Hamza's avatar
Noomen Hamza committed
633 634
    return res;
}
635 636 637 638

/******************************************************************************
 *        FileMoniker_Reduce
 ******************************************************************************/
639 640 641
static HRESULT WINAPI
FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
                       IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
642
{
643
    TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
644

Noomen Hamza's avatar
Noomen Hamza committed
645 646
    if (ppmkReduced==NULL)
        return E_POINTER;
647

648
    IMoniker_AddRef(iface);
649

Noomen Hamza's avatar
Noomen Hamza committed
650 651 652 653
    *ppmkReduced=iface;

    return MK_S_REDUCED_TO_SELF;
}
654

655 656
/******************************************************************************
 *        FileMoniker_ComposeWith
657 658 659 660
 */
static HRESULT WINAPI
FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
                            BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
661
{
Noomen Hamza's avatar
Noomen Hamza committed
662 663
    HRESULT res;
    LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0;
664 665
    static const WCHAR twoPoint[]={'.','.',0};
    static const WCHAR bkSlash[]={'\\',0};
Noomen Hamza's avatar
Noomen Hamza committed
666 667 668
    IBindCtx *bind=0;
    int i=0,j=0,lastIdx1=0,lastIdx2=0;
    DWORD mkSys;
669

670
    TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
671

Noomen Hamza's avatar
Noomen Hamza committed
672 673 674 675 676 677 678
    if (ppmkComposite==NULL)
        return E_POINTER;

    if (pmkRight==NULL)
	return E_INVALIDARG;

    *ppmkComposite=0;
679

Noomen Hamza's avatar
Noomen Hamza committed
680 681
    IMoniker_IsSystemMoniker(pmkRight,&mkSys);

Austin English's avatar
Austin English committed
682
    /* check if we have two FileMonikers to compose or not */
Noomen Hamza's avatar
Noomen Hamza committed
683 684 685 686
    if(mkSys==MKSYS_FILEMONIKER){

        CreateBindCtx(0,&bind);

687
        IMoniker_GetDisplayName(iface,bind,NULL,&str1);
Noomen Hamza's avatar
Noomen Hamza committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
        IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2);

        /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */
        lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1;
        lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1;

        if ((lastIdx1==-1 && lastIdx2>-1)||(lastIdx1==1 && lstrcmpW(strDec1[0],twoPoint)==0))
            return MK_E_SYNTAX;

        if(lstrcmpW(strDec1[lastIdx1],bkSlash)==0)
            lastIdx1--;

        /* for etch "..\" in the left of str2 remove the right element from str1 */
        for(i=0; ( (lastIdx1>=0) && (strDec2[i]!=NULL) && (lstrcmpW(strDec2[i],twoPoint)==0) ) ;i+=2){

            lastIdx1-=2;
        }

        /* the length of the composed path string  is raised by the sum of the two paths lengths  */
        newStr=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1));
708

Noomen Hamza's avatar
Noomen Hamza committed
709 710 711 712 713
	  if (newStr==NULL)
		return E_OUTOFMEMORY;

        /* new path is the concatenation of the rest of str1 and str2 */
        for(*newStr=0,j=0;j<=lastIdx1;j++)
714
            strcatW(newStr,strDec1[j]);
Noomen Hamza's avatar
Noomen Hamza committed
715 716

        if ((strDec2[i]==NULL && lastIdx1>-1 && lastIdx2>-1) || lstrcmpW(strDec2[i],bkSlash)!=0)
717
            strcatW(newStr,bkSlash);
718

Noomen Hamza's avatar
Noomen Hamza committed
719
        for(j=i;j<=lastIdx2;j++)
720
            strcatW(newStr,strDec2[j]);
721

Noomen Hamza's avatar
Noomen Hamza committed
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
        /* create a new moniker with the new string */
        res=CreateFileMoniker(newStr,ppmkComposite);

        /* free all strings space memory used by this function */
        HeapFree(GetProcessHeap(),0,newStr);

        for(i=0; strDec1[i]!=NULL;i++)
            CoTaskMemFree(strDec1[i]);
        for(i=0; strDec2[i]!=NULL;i++)
            CoTaskMemFree(strDec2[i]);
        CoTaskMemFree(strDec1);
        CoTaskMemFree(strDec2);

        CoTaskMemFree(str1);
        CoTaskMemFree(str2);

        return res;
    }
    else if(mkSys==MKSYS_ANTIMONIKER){

        *ppmkComposite=NULL;
        return S_OK;
    }
    else if (fOnlyIfNotGeneric){

        *ppmkComposite=NULL;
        return MK_E_NEEDGENERIC;
    }
    else

        return CreateGenericComposite(iface,pmkRight,ppmkComposite);
753 754 755 756
}

/******************************************************************************
 *        FileMoniker_Enum
757 758 759
 */
static HRESULT WINAPI
FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
760
{
761
    TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
762

Noomen Hamza's avatar
Noomen Hamza committed
763 764
    if (ppenumMoniker == NULL)
        return E_POINTER;
765

Noomen Hamza's avatar
Noomen Hamza committed
766
    *ppenumMoniker = NULL;
767

Noomen Hamza's avatar
Noomen Hamza committed
768
    return S_OK;
769 770 771 772
}

/******************************************************************************
 *        FileMoniker_IsEqual
773 774 775
 */
static HRESULT WINAPI
FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
776
{
777
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
Noomen Hamza's avatar
Noomen Hamza committed
778 779 780 781
    CLSID clsid;
    LPOLESTR filePath;
    IBindCtx* bind;
    HRESULT res;
782

783
    TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
784

Noomen Hamza's avatar
Noomen Hamza committed
785 786 787 788 789 790 791 792
    if (pmkOtherMoniker==NULL)
        return S_FALSE;

    IMoniker_GetClassID(pmkOtherMoniker,&clsid);

    if (!IsEqualCLSID(&clsid,&CLSID_FileMoniker))
        return S_FALSE;

793 794
    res = CreateBindCtx(0,&bind);
    if (FAILED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
795

796
    res = S_FALSE;
797
    if (SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath))) {
798 799
	if (!lstrcmpiW(filePath, This->filePathName))
            res = S_OK;
800 801
	CoTaskMemFree(filePath);
    }
802

803 804
    IBindCtx_Release(bind);
    return res;
805 806 807 808
}

/******************************************************************************
 *        FileMoniker_Hash
809 810 811
 */
static HRESULT WINAPI
FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
812
{
813
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
814

Noomen Hamza's avatar
Noomen Hamza committed
815 816 817
    int  h = 0,i,skip,len;
    int  off = 0;
    LPOLESTR val;
818

Noomen Hamza's avatar
Noomen Hamza committed
819 820
    if (pdwHash==NULL)
        return E_POINTER;
821

Noomen Hamza's avatar
Noomen Hamza committed
822 823 824 825 826 827 828 829 830 831 832 833 834
    val =  This->filePathName;
    len = lstrlenW(val);

    if (len < 16) {
        for (i = len ; i > 0; i--) {
            h = (h * 37) + val[off++];
 	}
    } else {
        /* only sample some characters */
 	skip = len / 8;
 	for (i = len ; i > 0; i -= skip, off += skip) {
            h = (h * 39) + val[off];
 	}
835
    }
Noomen Hamza's avatar
Noomen Hamza committed
836 837 838 839

    *pdwHash=h;

    return S_OK;
840 841 842 843
}

/******************************************************************************
 *        FileMoniker_IsRunning
844 845 846 847
 */
static HRESULT WINAPI
FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                          IMoniker* pmkNewlyRunning)
848
{
Noomen Hamza's avatar
Noomen Hamza committed
849 850
    IRunningObjectTable* rot;
    HRESULT res;
851

852
    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
853

Noomen Hamza's avatar
Noomen Hamza committed
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
    if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) )
        return S_OK;

    if (pbc==NULL)
        return E_POINTER;

    res=IBindCtx_GetRunningObjectTable(pbc,&rot);

    if (FAILED(res))
        return res;

    res = IRunningObjectTable_IsRunning(rot,iface);

    IRunningObjectTable_Release(rot);

    return res;
870 871 872 873 874
}

/******************************************************************************
 *        FileMoniker_GetTimeOfLastChange
 ******************************************************************************/
875 876 877
static HRESULT WINAPI
FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
                                    IMoniker* pmkToLeft, FILETIME* pFileTime)
878
{
879
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
Noomen Hamza's avatar
Noomen Hamza committed
880 881 882
    IRunningObjectTable* rot;
    HRESULT res;
    WIN32_FILE_ATTRIBUTE_DATA info;
883

884
    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime);
885

Noomen Hamza's avatar
Noomen Hamza committed
886 887 888 889 890 891 892 893 894 895 896 897 898
    if (pFileTime==NULL)
        return E_POINTER;

    if (pmkToLeft!=NULL)
        return E_INVALIDARG;

    res=IBindCtx_GetRunningObjectTable(pbc,&rot);

    if (FAILED(res))
        return res;

    res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime);

899
    if (FAILED(res)){ /* the moniker is not registered */
Noomen Hamza's avatar
Noomen Hamza committed
900 901 902

        if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info))
            return MK_E_NOOBJECT;
903

Noomen Hamza's avatar
Noomen Hamza committed
904
        *pFileTime=info.ftLastWriteTime;
905
    }
Noomen Hamza's avatar
Noomen Hamza committed
906 907

    return S_OK;
908 909 910 911
}

/******************************************************************************
 *        FileMoniker_Inverse
912 913 914
 */
static HRESULT WINAPI
FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
915
{
916
    TRACE("(%p,%p)\n",iface,ppmk);
917

Noomen Hamza's avatar
Noomen Hamza committed
918
    return CreateAntiMoniker(ppmk);
919 920 921 922
}

/******************************************************************************
 *        FileMoniker_CommonPrefixWith
923 924 925
 */
static HRESULT WINAPI
FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
926
{
927

Noomen Hamza's avatar
Noomen Hamza committed
928 929 930 931 932
    LPOLESTR pathThis,pathOther,*stringTable1,*stringTable2,commonPath;
    IBindCtx *pbind;
    DWORD mkSys;
    ULONG nb1,nb2,i,sameIdx;
    BOOL machimeNameCase=FALSE;
933

Noomen Hamza's avatar
Noomen Hamza committed
934 935 936 937 938
    if (ppmkPrefix==NULL)
        return E_POINTER;

    if (pmkOther==NULL)
        return E_INVALIDARG;
939

Noomen Hamza's avatar
Noomen Hamza committed
940
    *ppmkPrefix=0;
941

Noomen Hamza's avatar
Noomen Hamza committed
942 943 944 945
    /* check if we have the same type of moniker */
    IMoniker_IsSystemMoniker(pmkOther,&mkSys);

    if(mkSys==MKSYS_FILEMONIKER){
946
        HRESULT ret;
Noomen Hamza's avatar
Noomen Hamza committed
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963

        CreateBindCtx(0,&pbind);

        /* create a string based on common part of the two paths */

        IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis);
        IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther);

        nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1);
        nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2);

        if (nb1==0 || nb2==0)
            return MK_E_NOPREFIX;

        commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1));

        *commonPath=0;
964

Noomen Hamza's avatar
Noomen Hamza committed
965 966 967 968 969 970 971 972 973 974 975 976 977
        for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) &&
                         (stringTable2[sameIdx]!=NULL) &&
                         (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++);

        if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){

            machimeNameCase=TRUE;

            for(i=2;i<sameIdx;i++)

                if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){
                    machimeNameCase=FALSE;
                    break;
978
            }
Noomen Hamza's avatar
Noomen Hamza committed
979 980 981 982
        }

        if (machimeNameCase && *stringTable1[sameIdx-1]=='\\')
            sameIdx--;
983

Noomen Hamza's avatar
Noomen Hamza committed
984
        if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
            ret = MK_E_NOPREFIX;
        else
        {
            for(i=0;i<sameIdx;i++)
                strcatW(commonPath,stringTable1[i]);
    
            for(i=0;i<nb1;i++)
                CoTaskMemFree(stringTable1[i]);
    
            CoTaskMemFree(stringTable1);
    
            for(i=0;i<nb2;i++)
                CoTaskMemFree(stringTable2[i]);
    
            CoTaskMemFree(stringTable2);
    
            ret = CreateFileMoniker(commonPath,ppmkPrefix);
        }
Noomen Hamza's avatar
Noomen Hamza committed
1003
        HeapFree(GetProcessHeap(),0,commonPath);
1004
        return ret;
Noomen Hamza's avatar
Noomen Hamza committed
1005 1006 1007 1008 1009 1010 1011
    }
    else
        return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
}

/******************************************************************************
 *        DecomposePath (local function)
1012 1013
 */
int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable)
Noomen Hamza's avatar
Noomen Hamza committed
1014
{
1015
    static const WCHAR bSlash[] = {'\\',0};
1016 1017
    LPOLESTR word;
    int i=0,j,tabIndex=0, ret=0;
Noomen Hamza's avatar
Noomen Hamza committed
1018 1019 1020 1021
    LPOLESTR *strgtable ;

    int len=lstrlenW(str);

1022 1023
    TRACE("%s, %p\n", debugstr_w(str), *stringTable);

1024
    strgtable = CoTaskMemAlloc(len*sizeof(WCHAR));
1025

Noomen Hamza's avatar
Noomen Hamza committed
1026 1027
    if (strgtable==NULL)
	return E_OUTOFMEMORY;
1028

1029 1030 1031 1032 1033 1034 1035 1036
    word = CoTaskMemAlloc((len + 1)*sizeof(WCHAR));

    if (word==NULL)
    {
        ret = E_OUTOFMEMORY;
        goto lend;
    }

Noomen Hamza's avatar
Noomen Hamza committed
1037 1038 1039 1040 1041 1042 1043
    while(str[i]!=0){

        if(str[i]==bSlash[0]){

            strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR));

            if (strgtable[tabIndex]==NULL)
1044 1045 1046 1047
            {
                ret = E_OUTOFMEMORY;
                goto lend;
            }
Noomen Hamza's avatar
Noomen Hamza committed
1048

1049
            strcpyW(strgtable[tabIndex++],bSlash);
Noomen Hamza's avatar
Noomen Hamza committed
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063

            i++;

        }
        else {

            for(j=0; str[i]!=0 && str[i]!=bSlash[0] ; i++,j++)
                word[j]=str[i];

            word[j]=0;

            strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1));

            if (strgtable[tabIndex]==NULL)
1064 1065 1066 1067
            {
                ret = E_OUTOFMEMORY;
                goto lend;
            }
Noomen Hamza's avatar
Noomen Hamza committed
1068

1069
            strcpyW(strgtable[tabIndex++],word);
Noomen Hamza's avatar
Noomen Hamza committed
1070 1071 1072
        }
    }
    strgtable[tabIndex]=NULL;
1073

Noomen Hamza's avatar
Noomen Hamza committed
1074
    *stringTable=strgtable;
1075

1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
    ret = tabIndex;

lend:
    if (ret < 0)
    {
        for (i = 0; i < tabIndex; i++)
            CoTaskMemFree(strgtable[i]);

        CoTaskMemFree(strgtable);
    }

    if (word)
        CoTaskMemFree(word);

    return ret;
1091 1092 1093 1094
}

/******************************************************************************
 *        FileMoniker_RelativePathTo
1095 1096 1097
 */
static HRESULT WINAPI
FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
1098
{
Noomen Hamza's avatar
Noomen Hamza committed
1099 1100 1101 1102
    IBindCtx *bind;
    HRESULT res;
    LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
    DWORD len1=0,len2=0,sameIdx=0,j=0;
1103
    static const WCHAR back[] ={'.','.','\\',0};
1104

1105
    TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
1106

Noomen Hamza's avatar
Noomen Hamza committed
1107 1108
    if (ppmkRelPath==NULL)
        return E_POINTER;
1109

Noomen Hamza's avatar
Noomen Hamza committed
1110 1111
    if (pmOther==NULL)
        return E_INVALIDARG;
1112

Noomen Hamza's avatar
Noomen Hamza committed
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
    res=CreateBindCtx(0,&bind);
    if (FAILED(res))
	return res;

    res=IMoniker_GetDisplayName(iface,bind,NULL,&str1);
    if (FAILED(res))
	return res;
    res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2);
    if (FAILED(res))
	return res;

    len1=FileMonikerImpl_DecomposePath(str1,&tabStr1);
    len2=FileMonikerImpl_DecomposePath(str2,&tabStr2);

    if (FAILED(len1) || FAILED(len2))
	return E_OUTOFMEMORY;
1129

Noomen Hamza's avatar
Noomen Hamza committed
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
    /* count the number of similar items from the begin of the two paths */
    for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) &&
		   (tabStr2[sameIdx]!=NULL) &&
               (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++);

    /* begin the construction of relativePath */
    /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */
    /* by "..\\" in the begin */
    relPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2)));

    *relPath=0;

    if (len2>0 && !(len1==1 && len2==1 && sameIdx==0))
        for(j=sameIdx;(tabStr1[j] != NULL); j++)
            if (*tabStr1[j]!='\\')
1145
                strcatW(relPath,back);
Noomen Hamza's avatar
Noomen Hamza committed
1146 1147 1148

    /* add items of the second path (similar items with the first path are not included) to the relativePath */
    for(j=sameIdx;tabStr2[j]!=NULL;j++)
1149
        strcatW(relPath,tabStr2[j]);
1150

Noomen Hamza's avatar
Noomen Hamza committed
1151
    res=CreateFileMoniker(relPath,ppmkRelPath);
1152

Noomen Hamza's avatar
Noomen Hamza committed
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
    for(j=0; tabStr1[j]!=NULL;j++)
        CoTaskMemFree(tabStr1[j]);
    for(j=0; tabStr2[j]!=NULL;j++)
        CoTaskMemFree(tabStr2[j]);
    CoTaskMemFree(tabStr1);
    CoTaskMemFree(tabStr2);
    CoTaskMemFree(str1);
    CoTaskMemFree(str2);
    HeapFree(GetProcessHeap(),0,relPath);

    if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0))
        return MK_S_HIM;

    return res;
1167 1168 1169 1170
}

/******************************************************************************
 *        FileMoniker_GetDisplayName
1171 1172 1173 1174
 */
static HRESULT WINAPI
FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
                               IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1175
{
1176
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
1177

Noomen Hamza's avatar
Noomen Hamza committed
1178
    int len=lstrlenW(This->filePathName);
1179

1180
    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
Noomen Hamza's avatar
Noomen Hamza committed
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191

    if (ppszDisplayName==NULL)
        return E_POINTER;

    if (pmkToLeft!=NULL)
        return E_INVALIDARG;

    *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
    if (*ppszDisplayName==NULL)
        return E_OUTOFMEMORY;

1192
    strcpyW(*ppszDisplayName,This->filePathName);
1193

Robert Shearman's avatar
Robert Shearman committed
1194 1195
    TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
    
Noomen Hamza's avatar
Noomen Hamza committed
1196
    return S_OK;
1197 1198 1199 1200
}

/******************************************************************************
 *        FileMoniker_ParseDisplayName
1201 1202 1203 1204
 */
static HRESULT WINAPI
FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                     LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
1205
{
1206
    FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
1207 1208 1209 1210
    return E_NOTIMPL;
}

/******************************************************************************
Andreas Mohr's avatar
Andreas Mohr committed
1211
 *        FileMoniker_IsSystemMoniker
1212 1213 1214
 */
static HRESULT WINAPI
FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1215
{
1216
    TRACE("(%p,%p)\n",iface,pwdMksys);
Noomen Hamza's avatar
Noomen Hamza committed
1217 1218 1219

    if (!pwdMksys)
        return E_POINTER;
1220

Noomen Hamza's avatar
Noomen Hamza committed
1221 1222 1223 1224 1225 1226 1227
    (*pwdMksys)=MKSYS_FILEMONIKER;

    return S_OK;
}

/*******************************************************************************
 *        FileMonikerIROTData_QueryInterface
1228 1229 1230
 */
static HRESULT WINAPI
FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
Noomen Hamza's avatar
Noomen Hamza committed
1231 1232
{

1233
    IMoniker *This = impl_from_IROTData(iface);
Noomen Hamza's avatar
Noomen Hamza committed
1234

Robert Shearman's avatar
Robert Shearman committed
1235
    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
Noomen Hamza's avatar
Noomen Hamza committed
1236 1237 1238 1239 1240 1241 1242

    return FileMonikerImpl_QueryInterface(This, riid, ppvObject);
}

/***********************************************************************
 *        FileMonikerIROTData_AddRef
 */
1243 1244
static ULONG WINAPI
FileMonikerROTDataImpl_AddRef(IROTData *iface)
Noomen Hamza's avatar
Noomen Hamza committed
1245
{
1246
    IMoniker *This = impl_from_IROTData(iface);
1247

1248
    TRACE("(%p)\n",This);
Noomen Hamza's avatar
Noomen Hamza committed
1249

1250
    return IMoniker_AddRef(This);
Noomen Hamza's avatar
Noomen Hamza committed
1251 1252 1253 1254 1255
}

/***********************************************************************
 *        FileMonikerIROTData_Release
 */
1256 1257
static ULONG WINAPI
FileMonikerROTDataImpl_Release(IROTData* iface)
Noomen Hamza's avatar
Noomen Hamza committed
1258
{
1259
    IMoniker *This = impl_from_IROTData(iface);
1260

1261
    TRACE("(%p)\n",This);
Noomen Hamza's avatar
Noomen Hamza committed
1262 1263 1264

    return FileMonikerImpl_Release(This);
}
1265

Noomen Hamza's avatar
Noomen Hamza committed
1266
/******************************************************************************
1267
 *        FileMonikerIROTData_GetComparisonData
1268 1269
 */
static HRESULT WINAPI
1270
FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData,
1271
                                          ULONG cbMax, ULONG* pcbData)
Noomen Hamza's avatar
Noomen Hamza committed
1272
{
1273
    IMoniker *This = impl_from_IROTData(iface);
1274 1275 1276 1277 1278
    FileMonikerImpl *This1 = (FileMonikerImpl *)This;
    int len = (strlenW(This1->filePathName)+1);
    int i;
    LPWSTR pszFileName;

1279
    TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290

    *pcbData = sizeof(CLSID) + len * sizeof(WCHAR);
    if (cbMax < *pcbData)
        return E_OUTOFMEMORY;

    memcpy(pbData, &CLSID_FileMoniker, sizeof(CLSID));
    pszFileName = (LPWSTR)(pbData+sizeof(CLSID));
    for (i = 0; i < len; i++)
        pszFileName[i] = toupperW(This1->filePathName[i]);

    return S_OK;
1291 1292
}

1293 1294 1295 1296
/*
 * Virtual function table for the FileMonikerImpl class which include IPersist,
 * IPersistStream and IMoniker functions.
 */
1297
static const IMonikerVtbl VT_FileMonikerImpl =
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
{
    FileMonikerImpl_QueryInterface,
    FileMonikerImpl_AddRef,
    FileMonikerImpl_Release,
    FileMonikerImpl_GetClassID,
    FileMonikerImpl_IsDirty,
    FileMonikerImpl_Load,
    FileMonikerImpl_Save,
    FileMonikerImpl_GetSizeMax,
    FileMonikerImpl_BindToObject,
    FileMonikerImpl_BindToStorage,
    FileMonikerImpl_Reduce,
    FileMonikerImpl_ComposeWith,
    FileMonikerImpl_Enum,
    FileMonikerImpl_IsEqual,
    FileMonikerImpl_Hash,
    FileMonikerImpl_IsRunning,
    FileMonikerImpl_GetTimeOfLastChange,
    FileMonikerImpl_Inverse,
    FileMonikerImpl_CommonPrefixWith,
    FileMonikerImpl_RelativePathTo,
    FileMonikerImpl_GetDisplayName,
    FileMonikerImpl_ParseDisplayName,
    FileMonikerImpl_IsSystemMoniker
};

/* Virtual function table for the IROTData class. */
1325
static const IROTDataVtbl VT_ROTDataImpl =
1326 1327 1328 1329
{
    FileMonikerROTDataImpl_QueryInterface,
    FileMonikerROTDataImpl_AddRef,
    FileMonikerROTDataImpl_Release,
1330
    FileMonikerROTDataImpl_GetComparisonData
1331 1332 1333 1334 1335
};

/******************************************************************************
 *         FileMoniker_Construct (local function)
 */
1336
static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
{
    int nb=0,i;
    int sizeStr=lstrlenW(lpszPathName);
    LPOLESTR *tabStr=0;
    static const WCHAR twoPoint[]={'.','.',0};
    static const WCHAR bkSlash[]={'\\',0};
    BYTE addBkSlash;

    TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName));

Austin English's avatar
Austin English committed
1347
    /* Initialize the virtual function table. */
1348 1349 1350
    This->lpvtbl1      = &VT_FileMonikerImpl;
    This->lpvtbl2      = &VT_ROTDataImpl;
    This->ref          = 0;
1351
    This->pMarshal     = NULL;
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404

    This->filePathName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1));

    if (This->filePathName==NULL)
        return E_OUTOFMEMORY;

    strcpyW(This->filePathName,lpszPathName);

    nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr);

    if (nb > 0 ){

        addBkSlash=1;
        if (lstrcmpW(tabStr[0],twoPoint)!=0)
            addBkSlash=0;
        else
            for(i=0;i<nb;i++){

                if ( (lstrcmpW(tabStr[i],twoPoint)!=0) && (lstrcmpW(tabStr[i],bkSlash)!=0) ){
                    addBkSlash=0;
                    break;
                }
                else

                    if (lstrcmpW(tabStr[i],bkSlash)==0 && i<nb-1 && lstrcmpW(tabStr[i+1],bkSlash)==0){
                        *tabStr[i]=0;
                        sizeStr--;
                        addBkSlash=0;
                        break;
                    }
            }

        if (lstrcmpW(tabStr[nb-1],bkSlash)==0)
            addBkSlash=0;

        This->filePathName=HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR));

        *This->filePathName=0;

        for(i=0;tabStr[i]!=NULL;i++)
            strcatW(This->filePathName,tabStr[i]);

        if (addBkSlash)
            strcatW(This->filePathName,bkSlash);
    }

    for(i=0; tabStr[i]!=NULL;i++)
        CoTaskMemFree(tabStr[i]);
    CoTaskMemFree(tabStr);

    return S_OK;
}

1405
/******************************************************************************
1406
 *        CreateFileMoniker (OLE32.@)
1407
 ******************************************************************************/
1408
HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk)
1409
{
Robert Shearman's avatar
Robert Shearman committed
1410 1411
    FileMonikerImpl* newFileMoniker;
    HRESULT  hr;
1412

Robert Shearman's avatar
Robert Shearman committed
1413
    TRACE("(%s,%p)\n",debugstr_w(lpszPathName),ppmk);
1414

Robert Shearman's avatar
Robert Shearman committed
1415
    if (!ppmk)
Noomen Hamza's avatar
Noomen Hamza committed
1416 1417
        return E_POINTER;

Robert Shearman's avatar
Robert Shearman committed
1418
    if(!lpszPathName)
Noomen Hamza's avatar
Noomen Hamza committed
1419
        return MK_E_SYNTAX;
1420

Robert Shearman's avatar
Robert Shearman committed
1421
    *ppmk=NULL;
1422

1423 1424
    newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));

Robert Shearman's avatar
Robert Shearman committed
1425
    if (!newFileMoniker)
Noomen Hamza's avatar
Noomen Hamza committed
1426
        return E_OUTOFMEMORY;
1427 1428 1429

    hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName);

Noomen Hamza's avatar
Noomen Hamza committed
1430
    if (SUCCEEDED(hr))
Robert Shearman's avatar
Robert Shearman committed
1431
	hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker,&IID_IMoniker,(void**)ppmk);
Noomen Hamza's avatar
Noomen Hamza committed
1432 1433
    else
        HeapFree(GetProcessHeap(),0,newFileMoniker);
1434 1435 1436

    return hr;
}
1437

1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
/* find a character from a set in reverse without the string having to be null-terminated */
static inline WCHAR *memrpbrkW(const WCHAR *ptr, size_t n, const WCHAR *accept)
{
    const WCHAR *end, *ret = NULL;
    for (end = ptr + n; ptr < end; ptr++) if (strchrW(accept, *ptr)) ret = ptr;
    return (WCHAR *)ret;
}

HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
                                          LPDWORD pchEaten, LPMONIKER *ppmk)
{
    LPCWSTR end;
    static const WCHAR wszSeparators[] = {':','\\','/','!',0};

    for (end = szDisplayName + strlenW(szDisplayName);
         end && (end != szDisplayName);
         end = memrpbrkW(szDisplayName, end - szDisplayName, wszSeparators))
    {
        HRESULT hr;
        IRunningObjectTable *rot;
        IMoniker *file_moniker;
        LPWSTR file_display_name;
        LPWSTR full_path_name;
        DWORD full_path_name_len;
        int len = end - szDisplayName;

        file_display_name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
        if (!file_display_name) return E_OUTOFMEMORY;
        memcpy(file_display_name, szDisplayName, len * sizeof(WCHAR));
        file_display_name[len] = '\0';

        hr = CreateFileMoniker(file_display_name, &file_moniker);
        if (FAILED(hr))
        {
            HeapFree(GetProcessHeap(), 0, file_display_name);
            return hr;
        }

        hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
        if (FAILED(hr))
        {
            HeapFree(GetProcessHeap(), 0, file_display_name);
            IMoniker_Release(file_moniker);
            return hr;
        }

        hr = IRunningObjectTable_IsRunning(rot, file_moniker);
        IRunningObjectTable_Release(rot);
        if (FAILED(hr))
        {
            HeapFree(GetProcessHeap(), 0, file_display_name);
            IMoniker_Release(file_moniker);
            return hr;
        }
        if (hr == S_OK)
        {
            TRACE("found running file moniker for %s\n", debugstr_w(file_display_name));
            *pchEaten = len;
            *ppmk = file_moniker;
            HeapFree(GetProcessHeap(), 0, file_display_name);
            return S_OK;
        }

        full_path_name_len = GetFullPathNameW(file_display_name, 0, NULL, NULL);
        if (!full_path_name_len)
        {
            HeapFree(GetProcessHeap(), 0, file_display_name);
            IMoniker_Release(file_moniker);
            return MK_E_SYNTAX;
        }
        full_path_name = HeapAlloc(GetProcessHeap(), 0, full_path_name_len * sizeof(WCHAR));
        if (!full_path_name)
        {
            HeapFree(GetProcessHeap(), 0, file_display_name);
            IMoniker_Release(file_moniker);
            return E_OUTOFMEMORY;
        }
        GetFullPathNameW(file_display_name, full_path_name_len, full_path_name, NULL);

        if (GetFileAttributesW(full_path_name) == INVALID_FILE_ATTRIBUTES)
            TRACE("couldn't open file %s\n", debugstr_w(full_path_name));
        else
        {
            TRACE("got file moniker for %s\n", debugstr_w(szDisplayName));
            *pchEaten = len;
            *ppmk = file_moniker;
            HeapFree(GetProcessHeap(), 0, file_display_name);
            HeapFree(GetProcessHeap(), 0, full_path_name);
            return S_OK;
        }
        HeapFree(GetProcessHeap(), 0, file_display_name);
        HeapFree(GetProcessHeap(), 0, full_path_name);
        IMoniker_Release(file_moniker);
    }

    return MK_E_CANTOPENFILE;
}


1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
static HRESULT WINAPI FileMonikerCF_QueryInterface(LPCLASSFACTORY iface,
                                                  REFIID riid, LPVOID *ppv)
{
    *ppv = NULL;
    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
    {
        *ppv = iface;
        IUnknown_AddRef(iface);
        return S_OK;
    }
    return E_NOINTERFACE;
}

static ULONG WINAPI FileMonikerCF_AddRef(LPCLASSFACTORY iface)
{
    return 2; /* non-heap based object */
}

static ULONG WINAPI FileMonikerCF_Release(LPCLASSFACTORY iface)
{
    return 1; /* non-heap based object */
}

static HRESULT WINAPI FileMonikerCF_CreateInstance(LPCLASSFACTORY iface,
    LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
{
    FileMonikerImpl* newFileMoniker;
    HRESULT  hr;
    static const WCHAR wszEmpty[] = { 0 };

    TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);

    *ppv = NULL;

    if (pUnk)
        return CLASS_E_NOAGGREGATION;

    newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
    if (!newFileMoniker)
        return E_OUTOFMEMORY;

    hr = FileMonikerImpl_Construct(newFileMoniker, wszEmpty);

    if (SUCCEEDED(hr))
	hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker, riid, ppv);
    if (FAILED(hr))
        HeapFree(GetProcessHeap(),0,newFileMoniker);

    return hr;
}

static HRESULT WINAPI FileMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
{
    FIXME("(%d), stub!\n",fLock);
    return S_OK;
}

static const IClassFactoryVtbl FileMonikerCFVtbl =
{
    FileMonikerCF_QueryInterface,
    FileMonikerCF_AddRef,
    FileMonikerCF_Release,
    FileMonikerCF_CreateInstance,
    FileMonikerCF_LockServer
};
static const IClassFactoryVtbl *FileMonikerCF = &FileMonikerCFVtbl;

HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv)
{
    return IClassFactory_QueryInterface((IClassFactory *)&FileMonikerCF, riid, ppv);
}