filemoniker.c 40.3 KB
Newer Older
1 2
/*
 * FileMonikers implementation
3
 *
4
 * Copyright 1999  Noomen Hamza
5 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20 21

#include <assert.h>
22
#include <stdarg.h>
Andreas Mohr's avatar
Andreas Mohr committed
23
#include <string.h>
24

25
#define COBJMACROS
26 27
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
28

29
#include "windef.h"
30
#include "winbase.h"
31
#include "winerror.h"
32
#include "winnls.h"
33
#include "wine/unicode.h"
34
#include "wine/debug.h"
Noomen Hamza's avatar
Noomen Hamza committed
35
#include "objbase.h"
36
#include "moniker.h"
Noomen Hamza's avatar
Noomen Hamza committed
37

38 39
#include "compobj_private.h"

40
WINE_DEFAULT_DEBUG_CHANNEL(ole);
41

42 43 44 45
const CLSID CLSID_FileMoniker = {
  0x303, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
};

Noomen Hamza's avatar
Noomen Hamza committed
46
/* filemoniker data structure */
47 48
typedef struct FileMonikerImpl{

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

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

56
    LONG ref; /* reference counter for this object */
57

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

60
    IUnknown *pMarshal; /* custom marshaler */
61 62
} FileMonikerImpl;

63 64 65 66 67
static inline IMoniker *impl_from_IROTData( IROTData *iface )
{
    return (IMoniker *)((char*)iface - FIELD_OFFSET(FileMonikerImpl, lpvtbl2));
}

Noomen Hamza's avatar
Noomen Hamza committed
68
/* Local function used by filemoniker implementation */
69 70
static HRESULT WINAPI FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
static HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* iface);
Noomen Hamza's avatar
Noomen Hamza committed
71

72 73
/*******************************************************************************
 *        FileMoniker_QueryInterface
74 75 76
 */
static HRESULT WINAPI
FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
77
{
78
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
79

80
    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
81

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

Noomen Hamza's avatar
Noomen Hamza committed
86
    /* Initialize the return parameter */
87
    *ppvObject = 0;
88

Noomen Hamza's avatar
Noomen Hamza committed
89 90 91 92 93 94 95
    /* 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;
96

Noomen Hamza's avatar
Noomen Hamza committed
97 98
    else if (IsEqualIID(&IID_IROTData, riid))
        *ppvObject = (IROTData*)&(This->lpvtbl2);
99 100 101 102 103 104 105 106 107
    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
108 109 110 111

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

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

Noomen Hamza's avatar
Noomen Hamza committed
116
    return S_OK;
117 118 119 120
}

/******************************************************************************
 *        FileMoniker_AddRef
121 122 123
 */
static ULONG WINAPI
FileMonikerImpl_AddRef(IMoniker* iface)
124
{
125
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
126

127
    TRACE("(%p)\n",iface);
128

129
    return InterlockedIncrement(&This->ref);
130 131 132 133
}

/******************************************************************************
 *        FileMoniker_Release
134 135 136
 */
static ULONG WINAPI
FileMonikerImpl_Release(IMoniker* iface)
137
{
138
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
139
    ULONG ref;
140

141
    TRACE("(%p)\n",iface);
142

143
    ref = InterlockedDecrement(&This->ref);
144

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

148
    return ref;
149 150 151 152
}

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

Noomen Hamza's avatar
Noomen Hamza committed
159 160
    if (pClassID==NULL)
        return E_POINTER;
161

Noomen Hamza's avatar
Noomen Hamza committed
162
    *pClassID = CLSID_FileMoniker;
163

Noomen Hamza's avatar
Noomen Hamza committed
164
    return S_OK;
165 166 167 168
}

/******************************************************************************
 *        FileMoniker_IsDirty
169 170 171 172 173 174 175
 *
 * 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)
176
{
177

178
    TRACE("(%p)\n",iface);
179

Noomen Hamza's avatar
Noomen Hamza committed
180
    return S_FALSE;
181 182 183 184
}

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

200
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
201

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

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

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

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

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

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

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

Noomen Hamza's avatar
Noomen Hamza committed
253
    res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
    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
273

274 275 276 277
    if (dwbuffer < 6)
        goto fail;

    bytesW=dwbuffer - 6;
278

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

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

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

298
    filePathW[len]=0;
Noomen Hamza's avatar
Noomen Hamza committed
299

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

305 306 307 308 309 310 311 312
    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
313
    return res;
314 315 316
}

/******************************************************************************
317
 *        FileMoniker_Save
318
 *
319
 * This function saves data of this object. In the beginning I thought
320
 * that I have just to write the filePath string on Stream. But, when I
321 322 323 324 325
 * tested this function with windows programs samples, I noticed that it
 * 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:
326 327 328 329
 * 1) WORD constant:zero
 * 2) length of the path string ("\0" included)
 * 3) path string type A
 * 4) DWORD constant : 0xDEADFFFF
330 331 332 333 334
 * 5) five DWORD constant: zero
 * 6) If we're only writing the multibyte version, 
 *     write a zero DWORD and finish.
 *
 * 7) DWORD: double-length of the the path string type W ("\0" not
335
 *    included)
336 337 338
 * 8) WORD constant: 0x3
 * 9) filePath unicode string.
 *
339 340 341
 */
static HRESULT WINAPI
FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
342
{
343
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
Noomen Hamza's avatar
Noomen Hamza committed
344 345 346

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

350 351 352
    static const DWORD DEADFFFF = 0xDEADFFFF;  /* Constants */
    static const DWORD ZERO     = 0;
    static const WORD  THREE    = 0x3;
Noomen Hamza's avatar
Noomen Hamza committed
353

354 355
    int i;
    BOOL bUsedDefault, bWriteWide;
Noomen Hamza's avatar
Noomen Hamza committed
356

357
    TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
Noomen Hamza's avatar
Noomen Hamza committed
358 359 360 361

    if (pStm==NULL)
        return E_POINTER;

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    /* write a 0 WORD */
    res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
    if (!SUCCEEDED(res)) return res;

    /* 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);
    if (!SUCCEEDED(res)) return res;

    /* 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
377
    HeapFree(GetProcessHeap(),0,filePathA);
378
    if (!SUCCEEDED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
379

380 381 382
    /* write a DWORD 0xDEADFFFF */
    res=IStream_Write(pStm,&DEADFFFF,sizeof(DWORD),NULL);
    if (!SUCCEEDED(res)) return res;
383

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

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
    /* 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
410

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

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

422 423 424 425
    /* try again, without the extra 6 */
    bytesW -= 6;
    res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
    if (!SUCCEEDED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
426

427 428 429
    /* write a WORD 3 */
    res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
    if (!SUCCEEDED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
430

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

    return res;
435 436 437 438
}

/******************************************************************************
 *        FileMoniker_GetSizeMax
439 440 441
 */
static HRESULT WINAPI
FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
442
{
443
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
444

445
    TRACE("(%p,%p)\n",iface,pcbSize);
446

447
    if (!pcbSize)
Noomen Hamza's avatar
Noomen Hamza committed
448 449
        return E_POINTER;

450 451 452 453 454
    /* 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
455 456

    return S_OK;
457 458 459
}

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

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

    return S_OK;
}

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

488
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
489

Noomen Hamza's avatar
Noomen Hamza committed
490 491
    *ppvResult=0;

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

    if(pmkToLeft==NULL){
495

Noomen Hamza's avatar
Noomen Hamza committed
496 497 498
        res=IBindCtx_GetRunningObjectTable(pbc,&prot);

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

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

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

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

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

        if (res==E_NOINTERFACE){

526
            res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
527

Noomen Hamza's avatar
Noomen Hamza committed
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
            if (res==E_NOINTERFACE)
                return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
        }
        if (pcf!=NULL){

            IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)ppf);

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

            if (SUCCEEDED(res)){

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

545
            FIXME("()\n");
546

Noomen Hamza's avatar
Noomen Hamza committed
547 548 549 550 551 552 553 554 555 556 557 558 559
            /*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);
                }
            }*/
        }
560
    }
Noomen Hamza's avatar
Noomen Hamza committed
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581

    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);
582

Noomen Hamza's avatar
Noomen Hamza committed
583
    return res;
584 585 586 587
}

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

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

    if (pmkToLeft==NULL){

        if (IsEqualIID(&IID_IStorage, riid)){

            /* get the file name */
604
            IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath);
Noomen Hamza's avatar
Noomen Hamza committed
605 606 607 608 609 610 611 612 613

            /* verifie if the file contains a storage object */
            res=StgIsStorageFile(filePath);

            if(res==S_OK){

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

                if (SUCCEEDED(res)){
614

Noomen Hamza's avatar
Noomen Hamza committed
615 616 617 618 619 620 621 622 623 624 625
                    *ppvObject=pstg;

                    IStorage_AddRef(pstg);

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

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

634 635
        return E_NOTIMPL;
    }
Noomen Hamza's avatar
Noomen Hamza committed
636 637
    return res;
}
638 639 640 641

/******************************************************************************
 *        FileMoniker_Reduce
 ******************************************************************************/
642 643 644
static HRESULT WINAPI
FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
                       IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
645
{
646
    TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
647

Noomen Hamza's avatar
Noomen Hamza committed
648 649
    if (ppmkReduced==NULL)
        return E_POINTER;
650

651
    IMoniker_AddRef(iface);
652

Noomen Hamza's avatar
Noomen Hamza committed
653 654 655 656
    *ppmkReduced=iface;

    return MK_S_REDUCED_TO_SELF;
}
657

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

673
    TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
674

Noomen Hamza's avatar
Noomen Hamza committed
675 676 677 678 679 680 681
    if (ppmkComposite==NULL)
        return E_POINTER;

    if (pmkRight==NULL)
	return E_INVALIDARG;

    *ppmkComposite=0;
682

Noomen Hamza's avatar
Noomen Hamza committed
683 684 685 686 687 688 689
    IMoniker_IsSystemMoniker(pmkRight,&mkSys);

    /* check if we have two filemonikers to compose or not */
    if(mkSys==MKSYS_FILEMONIKER){

        CreateBindCtx(0,&bind);

690
        IMoniker_GetDisplayName(iface,bind,NULL,&str1);
Noomen Hamza's avatar
Noomen Hamza committed
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
        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));
711

Noomen Hamza's avatar
Noomen Hamza committed
712 713 714 715 716
	  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++)
717
            strcatW(newStr,strDec1[j]);
Noomen Hamza's avatar
Noomen Hamza committed
718 719

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

Noomen Hamza's avatar
Noomen Hamza committed
722
        for(j=i;j<=lastIdx2;j++)
723
            strcatW(newStr,strDec2[j]);
724

Noomen Hamza's avatar
Noomen Hamza committed
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 753 754 755
        /* 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);
756 757 758 759
}

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

Noomen Hamza's avatar
Noomen Hamza committed
766 767
    if (ppenumMoniker == NULL)
        return E_POINTER;
768

Noomen Hamza's avatar
Noomen Hamza committed
769
    *ppenumMoniker = NULL;
770

Noomen Hamza's avatar
Noomen Hamza committed
771
    return S_OK;
772 773 774 775
}

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

786
    TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
787

Noomen Hamza's avatar
Noomen Hamza committed
788 789 790 791 792 793 794 795
    if (pmkOtherMoniker==NULL)
        return S_FALSE;

    IMoniker_GetClassID(pmkOtherMoniker,&clsid);

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

796 797
    res = CreateBindCtx(0,&bind);
    if (FAILED(res)) return res;
Noomen Hamza's avatar
Noomen Hamza committed
798

799 800 801 802 803 804
    if (SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath))) {
	int result = lstrcmpiW(filePath, This->filePathName);
	CoTaskMemFree(filePath);
        if ( result == 0 ) return S_OK;
    }
    return S_FALSE;
805

806 807 808 809
}

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

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

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

Noomen Hamza's avatar
Noomen Hamza committed
823 824 825 826 827 828 829 830 831 832 833 834 835
    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];
 	}
836
    }
Noomen Hamza's avatar
Noomen Hamza committed
837 838 839 840

    *pdwHash=h;

    return S_OK;
841 842 843 844
}

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

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

Noomen Hamza's avatar
Noomen Hamza committed
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
    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;
871 872 873 874 875
}

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

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

Noomen Hamza's avatar
Noomen Hamza committed
887 888 889 890 891 892 893 894 895 896 897 898 899
    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);

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

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

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

    return S_OK;
909 910 911 912
}

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

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

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

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

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

    if (pmkOther==NULL)
        return E_INVALIDARG;
940

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

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

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

        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;
965

Noomen Hamza's avatar
Noomen Hamza committed
966 967 968 969 970 971 972 973 974 975 976 977 978
        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;
979
            }
Noomen Hamza's avatar
Noomen Hamza committed
980 981 982 983
        }

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

Noomen Hamza's avatar
Noomen Hamza committed
985
        if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
            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
1004
        HeapFree(GetProcessHeap(),0,commonPath);
1005
        return ret;
Noomen Hamza's avatar
Noomen Hamza committed
1006 1007 1008 1009 1010 1011 1012
    }
    else
        return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
}

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

    int len=lstrlenW(str);

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

1025
    strgtable =CoTaskMemAlloc(len*sizeof(LPOLESTR));
1026

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

Noomen Hamza's avatar
Noomen Hamza committed
1030 1031 1032 1033 1034 1035 1036 1037 1038
    while(str[i]!=0){

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

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

            if (strgtable[tabIndex]==NULL)
	    	return E_OUTOFMEMORY;

1039
            strcpyW(strgtable[tabIndex++],bSlash);
Noomen Hamza's avatar
Noomen Hamza committed
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055

            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)
                return E_OUTOFMEMORY;

1056
            strcpyW(strgtable[tabIndex++],word);
Noomen Hamza's avatar
Noomen Hamza committed
1057 1058 1059
        }
    }
    strgtable[tabIndex]=NULL;
1060

Noomen Hamza's avatar
Noomen Hamza committed
1061
    *stringTable=strgtable;
1062

Noomen Hamza's avatar
Noomen Hamza committed
1063
    return tabIndex;
1064 1065 1066 1067
}

/******************************************************************************
 *        FileMoniker_RelativePathTo
1068 1069 1070
 */
static HRESULT WINAPI
FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
1071
{
Noomen Hamza's avatar
Noomen Hamza committed
1072 1073 1074 1075
    IBindCtx *bind;
    HRESULT res;
    LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
    DWORD len1=0,len2=0,sameIdx=0,j=0;
1076
    static const WCHAR back[] ={'.','.','\\',0};
1077

1078
    TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
1079

Noomen Hamza's avatar
Noomen Hamza committed
1080 1081
    if (ppmkRelPath==NULL)
        return E_POINTER;
1082

Noomen Hamza's avatar
Noomen Hamza committed
1083 1084
    if (pmOther==NULL)
        return E_INVALIDARG;
1085

Noomen Hamza's avatar
Noomen Hamza committed
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
    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;
1102

Noomen Hamza's avatar
Noomen Hamza committed
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
    /* 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]!='\\')
1118
                strcatW(relPath,back);
Noomen Hamza's avatar
Noomen Hamza committed
1119 1120 1121

    /* 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++)
1122
        strcatW(relPath,tabStr2[j]);
1123

Noomen Hamza's avatar
Noomen Hamza committed
1124
    res=CreateFileMoniker(relPath,ppmkRelPath);
1125

Noomen Hamza's avatar
Noomen Hamza committed
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
    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;
1140 1141 1142 1143
}

/******************************************************************************
 *        FileMoniker_GetDisplayName
1144 1145 1146 1147
 */
static HRESULT WINAPI
FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
                               IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1148
{
1149
    FileMonikerImpl *This = (FileMonikerImpl *)iface;
1150

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

1153
    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
Noomen Hamza's avatar
Noomen Hamza committed
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164

    if (ppszDisplayName==NULL)
        return E_POINTER;

    if (pmkToLeft!=NULL)
        return E_INVALIDARG;

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

1165
    strcpyW(*ppszDisplayName,This->filePathName);
1166

Robert Shearman's avatar
Robert Shearman committed
1167 1168
    TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
    
Noomen Hamza's avatar
Noomen Hamza committed
1169
    return S_OK;
1170 1171 1172 1173
}

/******************************************************************************
 *        FileMoniker_ParseDisplayName
1174 1175 1176 1177
 */
static HRESULT WINAPI
FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                     LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
1178
{
1179
    FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
1180 1181 1182 1183
    return E_NOTIMPL;
}

/******************************************************************************
Andreas Mohr's avatar
Andreas Mohr committed
1184
 *        FileMoniker_IsSystemMoniker
1185 1186 1187
 */
static HRESULT WINAPI
FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1188
{
1189
    TRACE("(%p,%p)\n",iface,pwdMksys);
Noomen Hamza's avatar
Noomen Hamza committed
1190 1191 1192

    if (!pwdMksys)
        return E_POINTER;
1193

Noomen Hamza's avatar
Noomen Hamza committed
1194 1195 1196 1197 1198 1199 1200
    (*pwdMksys)=MKSYS_FILEMONIKER;

    return S_OK;
}

/*******************************************************************************
 *        FileMonikerIROTData_QueryInterface
1201 1202 1203
 */
static HRESULT WINAPI
FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
Noomen Hamza's avatar
Noomen Hamza committed
1204 1205
{

1206
    IMoniker *This = impl_from_IROTData(iface);
Noomen Hamza's avatar
Noomen Hamza committed
1207

Robert Shearman's avatar
Robert Shearman committed
1208
    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
Noomen Hamza's avatar
Noomen Hamza committed
1209 1210 1211 1212 1213 1214 1215

    return FileMonikerImpl_QueryInterface(This, riid, ppvObject);
}

/***********************************************************************
 *        FileMonikerIROTData_AddRef
 */
1216 1217
static ULONG WINAPI
FileMonikerROTDataImpl_AddRef(IROTData *iface)
Noomen Hamza's avatar
Noomen Hamza committed
1218
{
1219
    IMoniker *This = impl_from_IROTData(iface);
1220

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

1223
    return IMoniker_AddRef(This);
Noomen Hamza's avatar
Noomen Hamza committed
1224 1225 1226 1227 1228
}

/***********************************************************************
 *        FileMonikerIROTData_Release
 */
1229 1230
static ULONG WINAPI
FileMonikerROTDataImpl_Release(IROTData* iface)
Noomen Hamza's avatar
Noomen Hamza committed
1231
{
1232
    IMoniker *This = impl_from_IROTData(iface);
1233

1234
    TRACE("(%p)\n",This);
Noomen Hamza's avatar
Noomen Hamza committed
1235 1236 1237

    return FileMonikerImpl_Release(This);
}
1238

Noomen Hamza's avatar
Noomen Hamza committed
1239 1240
/******************************************************************************
 *        FileMonikerIROTData_GetComparaisonData
1241 1242
 */
static HRESULT WINAPI
1243
FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData,
1244
                                          ULONG cbMax, ULONG* pcbData)
Noomen Hamza's avatar
Noomen Hamza committed
1245
{
1246
    IMoniker *This = impl_from_IROTData(iface);
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
    FileMonikerImpl *This1 = (FileMonikerImpl *)This;
    int len = (strlenW(This1->filePathName)+1);
    int i;
    LPWSTR pszFileName;

    TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData);

    *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;
1264 1265
}

1266 1267 1268 1269
/*
 * Virtual function table for the FileMonikerImpl class which include IPersist,
 * IPersistStream and IMoniker functions.
 */
1270
static const IMonikerVtbl VT_FileMonikerImpl =
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
{
    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. */
1298
static const IROTDataVtbl VT_ROTDataImpl =
1299 1300 1301 1302
{
    FileMonikerROTDataImpl_QueryInterface,
    FileMonikerROTDataImpl_AddRef,
    FileMonikerROTDataImpl_Release,
1303
    FileMonikerROTDataImpl_GetComparisonData
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
};

/******************************************************************************
 *         FileMoniker_Construct (local function)
 */
static HRESULT WINAPI
FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
{
    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));

    /* Initialize the virtual fgunction table. */
    This->lpvtbl1      = &VT_FileMonikerImpl;
    This->lpvtbl2      = &VT_ROTDataImpl;
    This->ref          = 0;
1325
    This->pMarshal     = NULL;
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 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

    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;
}

1379
/******************************************************************************
1380
 *        CreateFileMoniker (OLE32.@)
1381
 ******************************************************************************/
1382
HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk)
1383
{
Robert Shearman's avatar
Robert Shearman committed
1384 1385
    FileMonikerImpl* newFileMoniker;
    HRESULT  hr;
1386

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

Robert Shearman's avatar
Robert Shearman committed
1389
    if (!ppmk)
Noomen Hamza's avatar
Noomen Hamza committed
1390 1391
        return E_POINTER;

Robert Shearman's avatar
Robert Shearman committed
1392
    if(!lpszPathName)
Noomen Hamza's avatar
Noomen Hamza committed
1393
        return MK_E_SYNTAX;
1394

Robert Shearman's avatar
Robert Shearman committed
1395
    *ppmk=NULL;
1396

1397 1398
    newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));

Robert Shearman's avatar
Robert Shearman committed
1399
    if (!newFileMoniker)
Noomen Hamza's avatar
Noomen Hamza committed
1400
        return E_OUTOFMEMORY;
1401 1402 1403

    hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName);

Noomen Hamza's avatar
Noomen Hamza committed
1404
    if (SUCCEEDED(hr))
Robert Shearman's avatar
Robert Shearman committed
1405
	hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker,&IID_IMoniker,(void**)ppmk);
Noomen Hamza's avatar
Noomen Hamza committed
1406 1407
    else
        HeapFree(GetProcessHeap(),0,newFileMoniker);
1408 1409 1410

    return hr;
}
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 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

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);
}