[CMAKE]
[reactos.git] / dll / win32 / ole32 / filemoniker.c
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 }