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