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