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
impl_from_IMoniker(IMoniker * iface)50 static inline FileMonikerImpl *impl_from_IMoniker(IMoniker *iface)
51 {
52 return CONTAINING_RECORD(iface, FileMonikerImpl, IMoniker_iface);
53 }
54
impl_from_IROTData(IROTData * iface)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
FileMonikerImpl_QueryInterface(IMoniker * iface,REFIID riid,void ** ppvObject)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
FileMonikerImpl_AddRef(IMoniker * iface)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
FileMonikerImpl_Release(IMoniker * iface)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
FileMonikerImpl_GetClassID(IMoniker * iface,CLSID * pClassID)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
FileMonikerImpl_IsDirty(IMoniker * iface)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
FileMonikerImpl_Load(IMoniker * iface,IStream * pStm)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
FileMonikerImpl_Save(IMoniker * iface,IStream * pStm,BOOL fClearDirty)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
FileMonikerImpl_GetSizeMax(IMoniker * iface,ULARGE_INTEGER * pcbSize)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 *******************************************************************************/
FileMonikerImpl_Destroy(FileMonikerImpl * This)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
FileMonikerImpl_BindToObject(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riid,VOID ** ppvResult)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
FileMonikerImpl_BindToStorage(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riid,VOID ** ppvObject)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
FileMonikerImpl_Reduce(IMoniker * iface,IBindCtx * pbc,DWORD dwReduceHowFar,IMoniker ** ppmkToLeft,IMoniker ** ppmkReduced)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
free_stringtable(LPOLESTR * stringTable)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
FileMonikerImpl_ComposeWith(IMoniker * iface,IMoniker * pmkRight,BOOL fOnlyIfNotGeneric,IMoniker ** ppmkComposite)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
FileMonikerImpl_Enum(IMoniker * iface,BOOL fForward,IEnumMoniker ** ppenumMoniker)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
FileMonikerImpl_IsEqual(IMoniker * iface,IMoniker * pmkOtherMoniker)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
FileMonikerImpl_Hash(IMoniker * iface,DWORD * pdwHash)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
FileMonikerImpl_IsRunning(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,IMoniker * pmkNewlyRunning)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
FileMonikerImpl_GetTimeOfLastChange(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,FILETIME * pFileTime)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
FileMonikerImpl_Inverse(IMoniker * iface,IMoniker ** ppmk)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
FileMonikerImpl_CommonPrefixWith(IMoniker * iface,IMoniker * pmkOther,IMoniker ** ppmkPrefix)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 */
FileMonikerImpl_DecomposePath(LPCOLESTR str,LPOLESTR ** stringTable)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
FileMonikerImpl_RelativePathTo(IMoniker * iface,IMoniker * pmOther,IMoniker ** ppmkRelPath)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
FileMonikerImpl_GetDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR * ppszDisplayName)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
FileMonikerImpl_ParseDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR pszDisplayName,ULONG * pchEaten,IMoniker ** ppmkOut)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
FileMonikerImpl_IsSystemMoniker(IMoniker * iface,DWORD * pwdMksys)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
FileMonikerROTDataImpl_QueryInterface(IROTData * iface,REFIID riid,VOID ** ppvObject)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
FileMonikerROTDataImpl_AddRef(IROTData * iface)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
FileMonikerROTDataImpl_Release(IROTData * iface)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
FileMonikerROTDataImpl_GetComparisonData(IROTData * iface,BYTE * pbData,ULONG cbMax,ULONG * pcbData)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 */
FileMonikerImpl_Construct(FileMonikerImpl * This,LPCOLESTR lpszPathName)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 ******************************************************************************/
CreateFileMoniker(LPCOLESTR lpszPathName,IMoniker ** ppmk)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 */
memrpbrkW(const WCHAR * ptr,size_t n,const WCHAR * accept)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
FileMoniker_CreateFromDisplayName(LPBC pbc,LPCOLESTR szDisplayName,LPDWORD pchEaten,IMoniker ** ppmk)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
FileMoniker_CreateInstance(IClassFactory * iface,IUnknown * pUnk,REFIID riid,void ** ppv)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