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