winevulkan: Update to VK spec version 1.2.195.
[wine.git] / dlls / ole32 / filemoniker.c
blob794b4507942c24123145f3986cc50b9ed1162aa0
1 /*
2 * FileMonikers implementation
4 * Copyright 1999 Noomen Hamza
5 * Copyright 2007 Robert Shearman
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.
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.
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
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <string.h>
26 #define COBJMACROS
27 #define NONAMELESSUNION
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"
37 #include "compobj_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
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;
50 static inline FileMonikerImpl *impl_from_IMoniker(IMoniker *iface)
52 return CONTAINING_RECORD(iface, FileMonikerImpl, IMoniker_iface);
55 static inline FileMonikerImpl *impl_from_IROTData(IROTData *iface)
57 return CONTAINING_RECORD(iface, FileMonikerImpl, IROTData_iface);
60 static const IMonikerVtbl VT_FileMonikerImpl;
62 static FileMonikerImpl *unsafe_impl_from_IMoniker(IMoniker *iface)
64 if (iface->lpVtbl != &VT_FileMonikerImpl)
65 return NULL;
66 return CONTAINING_RECORD(iface, FileMonikerImpl, IMoniker_iface);
69 /* Local function used by filemoniker implementation */
70 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
72 /*******************************************************************************
73 * FileMoniker_QueryInterface
75 static HRESULT WINAPI FileMonikerImpl_QueryInterface(IMoniker *iface, REFIID riid, void **ppvObject)
77 FileMonikerImpl *This = impl_from_IMoniker(iface);
79 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppvObject);
81 if (!ppvObject)
82 return E_INVALIDARG;
84 *ppvObject = 0;
86 if (IsEqualIID(&IID_IUnknown, riid) ||
87 IsEqualIID(&IID_IPersist, riid) ||
88 IsEqualIID(&IID_IPersistStream,riid) ||
89 IsEqualIID(&IID_IMoniker, riid) ||
90 IsEqualGUID(&CLSID_FileMoniker, riid))
92 *ppvObject = iface;
94 else if (IsEqualIID(&IID_IROTData, riid))
95 *ppvObject = &This->IROTData_iface;
96 else if (IsEqualIID(&IID_IMarshal, riid))
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);
106 if (!*ppvObject)
107 return E_NOINTERFACE;
109 IMoniker_AddRef(iface);
111 return S_OK;
114 /******************************************************************************
115 * FileMoniker_AddRef
117 static ULONG WINAPI
118 FileMonikerImpl_AddRef(IMoniker* iface)
120 FileMonikerImpl *This = impl_from_IMoniker(iface);
122 TRACE("(%p)\n",iface);
124 return InterlockedIncrement(&This->ref);
127 static ULONG WINAPI FileMonikerImpl_Release(IMoniker* iface)
129 FileMonikerImpl *moniker = impl_from_IMoniker(iface);
130 ULONG ref = InterlockedDecrement(&moniker->ref);
132 TRACE("(%p, refcount %d)\n", iface, ref);
134 if (!ref)
136 if (moniker->pMarshal) IUnknown_Release(moniker->pMarshal);
137 HeapFree(GetProcessHeap(), 0, moniker->filePathName);
138 HeapFree(GetProcessHeap(), 0, moniker);
141 return ref;
144 /******************************************************************************
145 * FileMoniker_GetClassID
147 static HRESULT WINAPI
148 FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID)
150 TRACE("(%p,%p)\n",iface,pClassID);
152 if (pClassID==NULL)
153 return E_POINTER;
155 *pClassID = CLSID_FileMoniker;
157 return S_OK;
160 /******************************************************************************
161 * FileMoniker_IsDirty
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.
167 static HRESULT WINAPI
168 FileMonikerImpl_IsDirty(IMoniker* iface)
171 TRACE("(%p)\n",iface);
173 return S_FALSE;
176 /******************************************************************************
177 * FileMoniker_Load
179 * this function locates and reads from the stream the filePath string
180 * written by FileMonikerImpl_Save
182 static HRESULT WINAPI
183 FileMonikerImpl_Load(IMoniker* iface, IStream* pStm)
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;
195 TRACE("(%p,%p)\n",iface,pStm);
197 /* first WORD */
198 res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
199 if (bread!=sizeof(WORD))
201 WARN("Couldn't read 0 word\n");
202 goto fail;
205 /* read filePath string length (plus one) */
206 res=IStream_Read(pStm,&bytesA,sizeof(DWORD),&bread);
207 if (bread != sizeof(DWORD))
209 WARN("Couldn't read file string length\n");
210 goto fail;
213 /* read filePath string */
214 filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
215 if (!filePathA)
217 res = E_OUTOFMEMORY;
218 goto fail;
221 res=IStream_Read(pStm,filePathA,bytesA,&bread);
222 if (bread != bytesA)
224 WARN("Couldn't read file path string\n");
225 goto fail;
228 /* read the unknown value */
229 IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
230 if (bread != sizeof(WORD))
232 WARN("Couldn't read unknown value\n");
233 goto fail;
236 /* read the DEAD constant */
237 IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
238 if (bread != sizeof(WORD))
240 WARN("Couldn't read DEAD constant\n");
241 goto fail;
244 for(i=0;i<5;i++)
246 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
247 if (bread!=sizeof(DWORD))
249 WARN("Couldn't read 0 padding\n");
250 goto fail;
254 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
255 if (bread!=sizeof(DWORD))
256 goto fail;
258 if (!dwbuffer) /* No W-string */
260 bytesA--;
261 len=MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, bytesA, NULL, 0);
262 if (!len)
263 goto fail;
265 filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
266 if (!filePathW)
268 res = E_OUTOFMEMORY;
269 goto fail;
271 MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, -1, filePathW, len+1);
272 goto succeed;
275 if (dwbuffer < 6)
276 goto fail;
278 bytesW=dwbuffer - 6;
280 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
281 if (bread!=sizeof(DWORD) || dwbuffer!=bytesW)
282 goto fail;
284 res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
285 if (bread!=sizeof(WORD) || wbuffer!=0x3)
286 goto fail;
288 len=bytesW/sizeof(WCHAR);
289 filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
290 if(!filePathW)
292 res = E_OUTOFMEMORY;
293 goto fail;
295 res=IStream_Read(pStm,filePathW,bytesW,&bread);
296 if (bread!=bytesW)
297 goto fail;
299 filePathW[len]=0;
301 succeed:
302 HeapFree(GetProcessHeap(),0,filePathA);
303 HeapFree(GetProcessHeap(),0,This->filePathName);
304 This->filePathName=filePathW;
306 return S_OK;
308 fail:
309 HeapFree(GetProcessHeap(), 0, filePathA);
310 HeapFree(GetProcessHeap(), 0, filePathW);
312 if (SUCCEEDED(res))
313 res = E_FAIL;
314 return res;
317 /******************************************************************************
318 * FileMoniker_Save
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.
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.
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.
343 static HRESULT WINAPI
344 FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
346 FileMonikerImpl *This = impl_from_IMoniker(iface);
347 HRESULT res;
348 LPOLESTR filePathW=This->filePathName;
349 CHAR* filePathA;
350 DWORD bytesA, bytesW, len;
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;
357 int i;
358 BOOL bUsedDefault, bWriteWide;
360 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
362 if (pStm==NULL)
363 return E_POINTER;
365 /* write a 0 WORD */
366 res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
367 if (FAILED(res)) return res;
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;
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;
383 /* write a WORD 0xFFFF */
384 res=IStream_Write(pStm,&FFFF,sizeof(WORD),NULL);
385 if (FAILED(res)) return res;
387 /* write a WORD 0xDEAD */
388 res=IStream_Write(pStm,&DEAD,sizeof(WORD),NULL);
389 if (FAILED(res)) return res;
391 /* write 5 zero DWORDs */
392 for(i=0;i<5;i++)
394 res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
395 if (FAILED(res)) return res;
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
403 len = lstrlenW(filePathW);
404 bWriteWide = (bUsedDefault || (len > 0 && filePathW[len-1]=='\\' ));
405 if (!bWriteWide)
407 WCHAR* pch;
408 for(pch=filePathW;*pch;++pch)
410 if (*pch > 0xFF)
412 bWriteWide = TRUE;
413 break;
418 if (!bWriteWide)
419 return IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
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;
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;
431 /* write a WORD 3 */
432 res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
433 if (FAILED(res)) return res;
435 /* write W string (no 0) */
436 return IStream_Write(pStm,filePathW,bytesW,NULL);
439 /******************************************************************************
440 * FileMoniker_GetSizeMax
442 static HRESULT WINAPI
443 FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
445 FileMonikerImpl *This = impl_from_IMoniker(iface);
447 TRACE("(%p,%p)\n",iface,pcbSize);
449 if (!pcbSize)
450 return E_POINTER;
452 /* We could calculate exactly (see ...::Save()) but instead
453 * we'll make a quick over-estimate, like Windows (NT4, XP) does.
455 pcbSize->u.LowPart = 0x38 + 4 * lstrlenW(This->filePathName);
456 pcbSize->u.HighPart = 0;
458 return S_OK;
461 /******************************************************************************
462 * FileMoniker_BindToObject
464 static HRESULT WINAPI
465 FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
466 REFIID riid, VOID** ppvResult)
468 FileMonikerImpl *This = impl_from_IMoniker(iface);
469 HRESULT res=E_FAIL;
470 CLSID clsID;
471 IUnknown* pObj=0;
472 IRunningObjectTable *prot=0;
473 IPersistFile *ppf=0;
474 IClassFactory *pcf=0;
475 IClassActivator *pca=0;
477 *ppvResult=0;
479 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
481 if(pmkToLeft==NULL){
483 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
485 if (SUCCEEDED(res)){
486 /* if the requested class was loaded before ! we don't need to reload it */
487 res = IRunningObjectTable_GetObject(prot,iface,&pObj);
489 if (res != S_OK){
490 /* first activation of this class */
491 res=GetClassFile(This->filePathName,&clsID);
492 if (SUCCEEDED(res)){
494 res=CoCreateInstance(&clsID,NULL,CLSCTX_SERVER,&IID_IPersistFile,(void**)&ppf);
495 if (SUCCEEDED(res)){
497 res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
498 if (SUCCEEDED(res)){
500 pObj=(IUnknown*)ppf;
501 IUnknown_AddRef(pObj);
508 else{
509 res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf);
511 if (res==E_NOINTERFACE){
513 res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
515 if (res==E_NOINTERFACE)
516 return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
518 if (pcf!=NULL){
520 IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)&ppf);
522 res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
524 if (SUCCEEDED(res)){
526 pObj=(IUnknown*)ppf;
527 IUnknown_AddRef(pObj);
530 if (pca!=NULL){
532 FIXME("()\n");
534 /*res=GetClassFile(This->filePathName,&clsID);
536 if (SUCCEEDED(res)){
538 res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf);
540 if (SUCCEEDED(res)){
542 pObj=(IUnknown*)ppf;
543 IUnknown_AddRef(pObj);
549 if (pObj!=NULL){
550 /* get the requested interface from the loaded class */
551 res= IUnknown_QueryInterface(pObj,riid,ppvResult);
553 IBindCtx_RegisterObjectBound(pbc,*ppvResult);
555 IUnknown_Release(pObj);
558 if (prot!=NULL)
559 IRunningObjectTable_Release(prot);
561 if (ppf!=NULL)
562 IPersistFile_Release(ppf);
564 if (pca!=NULL)
565 IClassActivator_Release(pca);
567 if (pcf!=NULL)
568 IClassFactory_Release(pcf);
570 return res;
573 /******************************************************************************
574 * FileMoniker_BindToStorage
576 static HRESULT WINAPI
577 FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
578 REFIID riid, void **object)
580 FileMonikerImpl *moniker = impl_from_IMoniker(iface);
581 BIND_OPTS bind_opts;
582 HRESULT hr;
584 TRACE("(%p,%p,%p,%s,%p)\n", iface, pbc, pmkToLeft, debugstr_guid(riid), object);
586 if (!pbc)
587 return E_INVALIDARG;
589 bind_opts.cbStruct = sizeof(bind_opts);
590 hr = IBindCtx_GetBindOptions(pbc, &bind_opts);
591 if (FAILED(hr))
592 return hr;
594 if (!pmkToLeft)
596 if (IsEqualIID(&IID_IStorage, riid))
598 return StgOpenStorage(moniker->filePathName, NULL, bind_opts.grfMode, NULL, 0, (IStorage **)object);
600 else if ((IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)))
601 return E_FAIL;
602 else
603 return E_NOINTERFACE;
606 FIXME("(%p,%p,%p,%s,%p)\n", iface, pbc, pmkToLeft, debugstr_guid(riid), object);
608 return E_NOTIMPL;
611 static HRESULT WINAPI FileMonikerImpl_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD howfar,
612 IMoniker **toleft, IMoniker **reduced)
614 TRACE("%p, %p, %d, %p, %p.\n", iface, pbc, howfar, toleft, reduced);
616 if (!pbc || !reduced)
617 return E_INVALIDARG;
619 IMoniker_AddRef(iface);
620 *reduced = iface;
622 return MK_S_REDUCED_TO_SELF;
625 static void free_stringtable(LPOLESTR *stringTable)
627 int i;
629 for (i=0; stringTable[i]!=NULL; i++)
630 CoTaskMemFree(stringTable[i]);
631 CoTaskMemFree(stringTable);
634 static int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable)
636 LPOLESTR word;
637 int i=0,j,tabIndex=0, ret=0;
638 LPOLESTR *strgtable ;
640 int len=lstrlenW(str);
642 TRACE("%s, %p\n", debugstr_w(str), *stringTable);
644 strgtable = CoTaskMemAlloc((len + 1)*sizeof(*strgtable));
646 if (strgtable==NULL)
647 return E_OUTOFMEMORY;
649 word = CoTaskMemAlloc((len + 1)*sizeof(WCHAR));
651 if (word==NULL)
653 ret = E_OUTOFMEMORY;
654 goto lend;
657 while(str[i]!=0){
659 if (str[i] == L'\\')
662 strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR));
664 if (strgtable[tabIndex]==NULL)
666 ret = E_OUTOFMEMORY;
667 goto lend;
670 lstrcpyW(strgtable[tabIndex++], L"\\");
672 i++;
675 else {
677 for (j = 0; str[i] && str[i] != L'\\'; i++, j++)
678 word[j]=str[i];
680 word[j]=0;
682 strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1));
684 if (strgtable[tabIndex]==NULL)
686 ret = E_OUTOFMEMORY;
687 goto lend;
690 lstrcpyW(strgtable[tabIndex++],word);
693 strgtable[tabIndex]=NULL;
695 *stringTable=strgtable;
697 ret = tabIndex;
699 lend:
700 if (ret < 0)
702 for (i = 0; i < tabIndex; i++)
703 CoTaskMemFree(strgtable[i]);
705 CoTaskMemFree(strgtable);
708 CoTaskMemFree(word);
710 return ret;
713 /******************************************************************************
714 * FileMoniker_ComposeWith
716 static HRESULT WINAPI
717 FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
718 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
720 HRESULT res;
721 LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0;
722 IBindCtx *bind=0;
723 int i=0,j=0,lastIdx1=0,lastIdx2=0;
724 DWORD mkSys, order;
726 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
728 if (ppmkComposite==NULL)
729 return E_POINTER;
731 if (pmkRight==NULL)
732 return E_INVALIDARG;
734 *ppmkComposite=0;
736 IMoniker_IsSystemMoniker(pmkRight,&mkSys);
738 /* check if we have two FileMonikers to compose or not */
739 if(mkSys==MKSYS_FILEMONIKER){
741 CreateBindCtx(0,&bind);
743 IMoniker_GetDisplayName(iface,bind,NULL,&str1);
744 IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2);
746 /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */
747 lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1;
748 lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1;
750 if ((lastIdx1 == -1 && lastIdx2 > -1) || (lastIdx1 == 1 && !wcscmp(strDec1[0], L"..")))
751 res = MK_E_SYNTAX;
752 else{
753 if (!wcscmp(strDec1[lastIdx1], L"\\"))
754 lastIdx1--;
756 /* for each "..\" in the left of str2 remove the right element from str1 */
757 for (i = 0; lastIdx1 >= 0 && strDec2[i] && !wcscmp(strDec2[i], L".."); i += 2)
758 lastIdx1-=2;
760 /* the length of the composed path string is increased by the sum of the two paths' lengths */
761 newStr=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1));
763 if (newStr){
764 /* new path is the concatenation of the rest of str1 and str2 */
765 for(*newStr=0,j=0;j<=lastIdx1;j++)
766 lstrcatW(newStr,strDec1[j]);
768 if ((!strDec2[i] && lastIdx1 > -1 && lastIdx2 > -1) || wcscmp(strDec2[i], L"\\"))
769 lstrcatW(newStr, L"\\");
771 for(j=i;j<=lastIdx2;j++)
772 lstrcatW(newStr,strDec2[j]);
774 /* create a new moniker with the new string */
775 res=CreateFileMoniker(newStr,ppmkComposite);
777 /* free string memory used by this function */
778 HeapFree(GetProcessHeap(),0,newStr);
780 else res = E_OUTOFMEMORY;
783 free_stringtable(strDec1);
784 free_stringtable(strDec2);
786 CoTaskMemFree(str1);
787 CoTaskMemFree(str2);
789 return res;
791 else if (is_anti_moniker(pmkRight, &order))
793 return order > 1 ? create_anti_moniker(order - 1, ppmkComposite) : S_OK;
795 else if (fOnlyIfNotGeneric){
797 *ppmkComposite=NULL;
798 return MK_E_NEEDGENERIC;
800 else
802 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
805 /******************************************************************************
806 * FileMoniker_Enum
808 static HRESULT WINAPI
809 FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
811 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
813 if (ppenumMoniker == NULL)
814 return E_POINTER;
816 *ppenumMoniker = NULL;
818 return S_OK;
821 static HRESULT WINAPI FileMonikerImpl_IsEqual(IMoniker *iface, IMoniker *other)
823 FileMonikerImpl *moniker = impl_from_IMoniker(iface), *other_moniker;
825 TRACE("%p, %p.\n", iface, other);
827 if (!other)
828 return E_INVALIDARG;
830 other_moniker = unsafe_impl_from_IMoniker(other);
831 if (!other_moniker)
832 return S_FALSE;
834 return !wcsicmp(moniker->filePathName, other_moniker->filePathName) ? S_OK : S_FALSE;
837 /******************************************************************************
838 * FileMoniker_Hash
840 static HRESULT WINAPI
841 FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
843 FileMonikerImpl *This = impl_from_IMoniker(iface);
844 int h = 0,i,skip,len;
845 int off = 0;
846 LPOLESTR val;
848 if (pdwHash==NULL)
849 return E_POINTER;
851 val = This->filePathName;
852 len = lstrlenW(val);
854 if (len < 16) {
855 for (i = len ; i > 0; i--) {
856 h = (h * 37) + val[off++];
858 } else {
859 /* only sample some characters */
860 skip = len / 8;
861 for (i = len ; i > 0; i -= skip, off += skip) {
862 h = (h * 39) + val[off];
866 *pdwHash=h;
868 return S_OK;
871 /******************************************************************************
872 * FileMoniker_IsRunning
874 static HRESULT WINAPI
875 FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
876 IMoniker* pmkNewlyRunning)
878 IRunningObjectTable* rot;
879 HRESULT res;
881 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
883 if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) )
884 return S_OK;
886 if (pbc==NULL)
887 return E_POINTER;
889 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
891 if (FAILED(res))
892 return res;
894 res = IRunningObjectTable_IsRunning(rot,iface);
896 IRunningObjectTable_Release(rot);
898 return res;
901 /******************************************************************************
902 * FileMoniker_GetTimeOfLastChange
903 ******************************************************************************/
904 static HRESULT WINAPI
905 FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
906 IMoniker* pmkToLeft, FILETIME* pFileTime)
908 FileMonikerImpl *This = impl_from_IMoniker(iface);
909 IRunningObjectTable* rot;
910 HRESULT res;
911 WIN32_FILE_ATTRIBUTE_DATA info;
913 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime);
915 if (pFileTime==NULL)
916 return E_POINTER;
918 if (pmkToLeft!=NULL)
919 return E_INVALIDARG;
921 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
923 if (FAILED(res))
924 return res;
926 res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime);
928 if (FAILED(res)){ /* the moniker is not registered */
930 if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info))
931 return MK_E_NOOBJECT;
933 *pFileTime=info.ftLastWriteTime;
936 return S_OK;
939 /******************************************************************************
940 * FileMoniker_Inverse
942 static HRESULT WINAPI
943 FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
945 TRACE("(%p,%p)\n",iface,ppmk);
947 return CreateAntiMoniker(ppmk);
950 /******************************************************************************
951 * FileMoniker_CommonPrefixWith
953 static HRESULT WINAPI
954 FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
957 LPOLESTR pathThis = NULL, pathOther = NULL, *stringTable1 = NULL;
958 LPOLESTR *stringTable2 = NULL, commonPath = NULL;
959 IBindCtx *bindctx;
960 DWORD mkSys;
961 ULONG nb1,nb2,i,sameIdx;
962 BOOL machineNameCase = FALSE;
963 HRESULT ret;
965 if (ppmkPrefix==NULL)
966 return E_POINTER;
968 if (pmkOther==NULL)
969 return E_INVALIDARG;
971 *ppmkPrefix=0;
973 /* check if we have the same type of moniker */
974 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
975 if (mkSys != MKSYS_FILEMONIKER)
976 return MonikerCommonPrefixWith(iface, pmkOther, ppmkPrefix);
978 ret = CreateBindCtx(0, &bindctx);
979 if (FAILED(ret))
980 return ret;
982 /* create a string based on common part of the two paths */
983 ret = IMoniker_GetDisplayName(iface, bindctx, NULL, &pathThis);
984 if (FAILED(ret))
985 goto failed;
987 ret = IMoniker_GetDisplayName(pmkOther, bindctx, NULL, &pathOther);
988 if (FAILED(ret))
989 goto failed;
991 nb1 = FileMonikerImpl_DecomposePath(pathThis, &stringTable1);
992 if (FAILED(nb1)) {
993 ret = nb1;
994 goto failed;
997 nb2 = FileMonikerImpl_DecomposePath(pathOther, &stringTable2);
998 if (FAILED(nb2)) {
999 ret = nb2;
1000 goto failed;
1003 if (nb1 == 0 || nb2 == 0) {
1004 ret = MK_E_NOPREFIX;
1005 goto failed;
1008 commonPath = CoTaskMemAlloc(sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1));
1009 if (!commonPath) {
1010 ret = E_OUTOFMEMORY;
1011 goto failed;
1014 *commonPath = 0;
1015 for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) &&
1016 (stringTable2[sameIdx]!=NULL) &&
1017 (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++);
1019 if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){
1020 machineNameCase = TRUE;
1022 for(i=2;i<sameIdx;i++)
1023 if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){
1024 machineNameCase = FALSE;
1025 break;
1029 if (machineNameCase && *stringTable1[sameIdx-1]=='\\')
1030 sameIdx--;
1032 if (machineNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
1033 ret = MK_E_NOPREFIX;
1034 else
1036 for (i = 0; i < sameIdx; i++)
1037 lstrcatW(commonPath,stringTable1[i]);
1038 ret = CreateFileMoniker(commonPath, ppmkPrefix);
1041 failed:
1042 IBindCtx_Release(bindctx);
1043 CoTaskMemFree(pathThis);
1044 CoTaskMemFree(pathOther);
1045 CoTaskMemFree(commonPath);
1046 if (stringTable1) free_stringtable(stringTable1);
1047 if (stringTable2) free_stringtable(stringTable2);
1049 return ret;
1052 /******************************************************************************
1053 * FileMoniker_RelativePathTo
1055 static HRESULT WINAPI
1056 FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
1058 IBindCtx *bind;
1059 HRESULT res;
1060 LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
1061 DWORD len1=0,len2=0,sameIdx=0,j=0;
1063 TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
1065 if (ppmkRelPath==NULL)
1066 return E_POINTER;
1068 if (pmOther==NULL)
1069 return E_INVALIDARG;
1071 res=CreateBindCtx(0,&bind);
1072 if (FAILED(res))
1073 return res;
1075 res=IMoniker_GetDisplayName(iface,bind,NULL,&str1);
1076 if (FAILED(res))
1077 return res;
1078 res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2);
1079 if (FAILED(res))
1080 return res;
1082 len1=FileMonikerImpl_DecomposePath(str1,&tabStr1);
1083 if (FAILED(len1))
1084 return E_OUTOFMEMORY;
1085 len2=FileMonikerImpl_DecomposePath(str2,&tabStr2);
1087 if (FAILED(len2))
1089 free_stringtable(tabStr1);
1090 return E_OUTOFMEMORY;
1093 /* count the number of similar items from the begin of the two paths */
1094 for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) &&
1095 (tabStr2[sameIdx]!=NULL) &&
1096 (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++);
1098 /* begin the construction of relativePath */
1099 /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */
1100 /* by "..\\" in the begin */
1101 relPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2)));
1103 *relPath=0;
1105 if (len2>0 && !(len1==1 && len2==1 && sameIdx==0))
1106 for(j=sameIdx;(tabStr1[j] != NULL); j++)
1107 if (*tabStr1[j]!='\\')
1108 lstrcatW(relPath, L"..\\");
1110 /* add items of the second path (similar items with the first path are not included) to the relativePath */
1111 for(j=sameIdx;tabStr2[j]!=NULL;j++)
1112 lstrcatW(relPath,tabStr2[j]);
1114 res=CreateFileMoniker(relPath,ppmkRelPath);
1116 free_stringtable(tabStr1);
1117 free_stringtable(tabStr2);
1118 CoTaskMemFree(str1);
1119 CoTaskMemFree(str2);
1120 HeapFree(GetProcessHeap(),0,relPath);
1122 if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0))
1123 return MK_S_HIM;
1125 return res;
1128 /******************************************************************************
1129 * FileMoniker_GetDisplayName
1131 static HRESULT WINAPI
1132 FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1133 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1135 FileMonikerImpl *This = impl_from_IMoniker(iface);
1136 int len=lstrlenW(This->filePathName);
1138 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1140 if (ppszDisplayName==NULL)
1141 return E_POINTER;
1143 if (pmkToLeft!=NULL)
1144 return E_INVALIDARG;
1146 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
1147 if (*ppszDisplayName==NULL)
1148 return E_OUTOFMEMORY;
1150 lstrcpyW(*ppszDisplayName,This->filePathName);
1152 TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
1154 return S_OK;
1157 /******************************************************************************
1158 * FileMoniker_ParseDisplayName
1160 static HRESULT WINAPI
1161 FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
1162 LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
1164 FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
1165 return E_NOTIMPL;
1168 /******************************************************************************
1169 * FileMoniker_IsSystemMoniker
1171 static HRESULT WINAPI
1172 FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1174 TRACE("(%p,%p)\n",iface,pwdMksys);
1176 if (!pwdMksys)
1177 return E_POINTER;
1179 (*pwdMksys)=MKSYS_FILEMONIKER;
1181 return S_OK;
1184 /*******************************************************************************
1185 * FileMonikerIROTData_QueryInterface
1187 static HRESULT WINAPI
1188 FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
1191 FileMonikerImpl *This = impl_from_IROTData(iface);
1193 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1195 return FileMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
1198 /***********************************************************************
1199 * FileMonikerIROTData_AddRef
1201 static ULONG WINAPI
1202 FileMonikerROTDataImpl_AddRef(IROTData *iface)
1204 FileMonikerImpl *This = impl_from_IROTData(iface);
1206 TRACE("(%p)\n",This);
1208 return IMoniker_AddRef(&This->IMoniker_iface);
1211 /***********************************************************************
1212 * FileMonikerIROTData_Release
1214 static ULONG WINAPI
1215 FileMonikerROTDataImpl_Release(IROTData* iface)
1217 FileMonikerImpl *This = impl_from_IROTData(iface);
1219 TRACE("(%p)\n",This);
1221 return FileMonikerImpl_Release(&This->IMoniker_iface);
1224 /******************************************************************************
1225 * FileMonikerIROTData_GetComparisonData
1227 static HRESULT WINAPI
1228 FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData,
1229 ULONG cbMax, ULONG* pcbData)
1231 FileMonikerImpl *This = impl_from_IROTData(iface);
1232 int len = lstrlenW(This->filePathName)+1;
1233 int i;
1234 LPWSTR pszFileName;
1236 TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1238 *pcbData = sizeof(CLSID) + len * sizeof(WCHAR);
1239 if (cbMax < *pcbData)
1240 return E_OUTOFMEMORY;
1242 memcpy(pbData, &CLSID_FileMoniker, sizeof(CLSID));
1243 pszFileName = (LPWSTR)(pbData+sizeof(CLSID));
1244 for (i = 0; i < len; i++)
1245 pszFileName[i] = towupper(This->filePathName[i]);
1247 return S_OK;
1251 * Virtual function table for the FileMonikerImpl class which include IPersist,
1252 * IPersistStream and IMoniker functions.
1254 static const IMonikerVtbl VT_FileMonikerImpl =
1256 FileMonikerImpl_QueryInterface,
1257 FileMonikerImpl_AddRef,
1258 FileMonikerImpl_Release,
1259 FileMonikerImpl_GetClassID,
1260 FileMonikerImpl_IsDirty,
1261 FileMonikerImpl_Load,
1262 FileMonikerImpl_Save,
1263 FileMonikerImpl_GetSizeMax,
1264 FileMonikerImpl_BindToObject,
1265 FileMonikerImpl_BindToStorage,
1266 FileMonikerImpl_Reduce,
1267 FileMonikerImpl_ComposeWith,
1268 FileMonikerImpl_Enum,
1269 FileMonikerImpl_IsEqual,
1270 FileMonikerImpl_Hash,
1271 FileMonikerImpl_IsRunning,
1272 FileMonikerImpl_GetTimeOfLastChange,
1273 FileMonikerImpl_Inverse,
1274 FileMonikerImpl_CommonPrefixWith,
1275 FileMonikerImpl_RelativePathTo,
1276 FileMonikerImpl_GetDisplayName,
1277 FileMonikerImpl_ParseDisplayName,
1278 FileMonikerImpl_IsSystemMoniker
1281 /* Virtual function table for the IROTData class. */
1282 static const IROTDataVtbl VT_ROTDataImpl =
1284 FileMonikerROTDataImpl_QueryInterface,
1285 FileMonikerROTDataImpl_AddRef,
1286 FileMonikerROTDataImpl_Release,
1287 FileMonikerROTDataImpl_GetComparisonData
1290 /******************************************************************************
1291 * FileMoniker_Construct (local function)
1293 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
1295 int nb=0,i;
1296 int sizeStr=lstrlenW(lpszPathName);
1297 LPOLESTR *tabStr=0;
1298 BOOL addBkSlash;
1300 TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName));
1302 /* Initialize the virtual function table. */
1303 This->IMoniker_iface.lpVtbl = &VT_FileMonikerImpl;
1304 This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1305 This->ref = 0;
1306 This->pMarshal = NULL;
1308 This->filePathName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1));
1310 if (This->filePathName==NULL)
1311 return E_OUTOFMEMORY;
1313 lstrcpyW(This->filePathName,lpszPathName);
1315 nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr);
1317 if (nb > 0 ){
1319 addBkSlash = TRUE;
1320 if (wcscmp(tabStr[0], L".."))
1321 addBkSlash = FALSE;
1322 else
1323 for(i=0;i<nb;i++){
1325 if (wcscmp(tabStr[i], L"..") && wcscmp(tabStr[i], L"\\"))
1327 addBkSlash = FALSE;
1328 break;
1330 else
1332 if (!wcscmp(tabStr[i], L"\\") && i < nb - 1 && !wcscmp(tabStr[i+1], L"\\"))
1334 *tabStr[i]=0;
1335 sizeStr--;
1336 addBkSlash = FALSE;
1337 break;
1341 if (!wcscmp(tabStr[nb-1], L"\\"))
1342 addBkSlash = FALSE;
1344 This->filePathName=HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR));
1346 *This->filePathName=0;
1348 for(i=0;tabStr[i]!=NULL;i++)
1349 lstrcatW(This->filePathName,tabStr[i]);
1351 if (addBkSlash)
1352 lstrcatW(This->filePathName, L"\\");
1355 free_stringtable(tabStr);
1357 return S_OK;
1360 /******************************************************************************
1361 * CreateFileMoniker (OLE32.@)
1362 ******************************************************************************/
1363 HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, IMoniker **ppmk)
1365 FileMonikerImpl* newFileMoniker;
1366 HRESULT hr;
1368 TRACE("(%s,%p)\n",debugstr_w(lpszPathName),ppmk);
1370 if (!ppmk)
1371 return E_POINTER;
1373 if(!lpszPathName)
1374 return MK_E_SYNTAX;
1376 *ppmk=NULL;
1378 newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
1380 if (!newFileMoniker)
1381 return E_OUTOFMEMORY;
1383 hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName);
1385 if (SUCCEEDED(hr))
1386 hr = IMoniker_QueryInterface(&newFileMoniker->IMoniker_iface,&IID_IMoniker,(void**)ppmk);
1387 else
1388 HeapFree(GetProcessHeap(),0,newFileMoniker);
1390 return hr;
1393 /* find a character from a set in reverse without the string having to be null-terminated */
1394 static inline WCHAR *memrpbrkW(const WCHAR *ptr, size_t n, const WCHAR *accept)
1396 const WCHAR *end, *ret = NULL;
1397 for (end = ptr + n; ptr < end; ptr++) if (wcschr(accept, *ptr)) ret = ptr;
1398 return (WCHAR *)ret;
1401 HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
1402 LPDWORD pchEaten, IMoniker **ppmk)
1404 LPCWSTR end;
1406 for (end = szDisplayName + lstrlenW(szDisplayName);
1407 end && (end != szDisplayName);
1408 end = memrpbrkW(szDisplayName, end - szDisplayName, L":\\/!"))
1410 HRESULT hr;
1411 IRunningObjectTable *rot;
1412 IMoniker *file_moniker;
1413 LPWSTR file_display_name;
1414 LPWSTR full_path_name;
1415 DWORD full_path_name_len;
1416 int len = end - szDisplayName;
1418 file_display_name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1419 if (!file_display_name) return E_OUTOFMEMORY;
1420 memcpy(file_display_name, szDisplayName, len * sizeof(WCHAR));
1421 file_display_name[len] = '\0';
1423 hr = CreateFileMoniker(file_display_name, &file_moniker);
1424 if (FAILED(hr))
1426 HeapFree(GetProcessHeap(), 0, file_display_name);
1427 return hr;
1430 hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
1431 if (FAILED(hr))
1433 HeapFree(GetProcessHeap(), 0, file_display_name);
1434 IMoniker_Release(file_moniker);
1435 return hr;
1438 hr = IRunningObjectTable_IsRunning(rot, file_moniker);
1439 IRunningObjectTable_Release(rot);
1440 if (FAILED(hr))
1442 HeapFree(GetProcessHeap(), 0, file_display_name);
1443 IMoniker_Release(file_moniker);
1444 return hr;
1446 if (hr == S_OK)
1448 TRACE("found running file moniker for %s\n", debugstr_w(file_display_name));
1449 *pchEaten = len;
1450 *ppmk = file_moniker;
1451 HeapFree(GetProcessHeap(), 0, file_display_name);
1452 return S_OK;
1455 full_path_name_len = GetFullPathNameW(file_display_name, 0, NULL, NULL);
1456 if (!full_path_name_len)
1458 HeapFree(GetProcessHeap(), 0, file_display_name);
1459 IMoniker_Release(file_moniker);
1460 return MK_E_SYNTAX;
1462 full_path_name = HeapAlloc(GetProcessHeap(), 0, full_path_name_len * sizeof(WCHAR));
1463 if (!full_path_name)
1465 HeapFree(GetProcessHeap(), 0, file_display_name);
1466 IMoniker_Release(file_moniker);
1467 return E_OUTOFMEMORY;
1469 GetFullPathNameW(file_display_name, full_path_name_len, full_path_name, NULL);
1471 if (GetFileAttributesW(full_path_name) == INVALID_FILE_ATTRIBUTES)
1472 TRACE("couldn't open file %s\n", debugstr_w(full_path_name));
1473 else
1475 TRACE("got file moniker for %s\n", debugstr_w(szDisplayName));
1476 *pchEaten = len;
1477 *ppmk = file_moniker;
1478 HeapFree(GetProcessHeap(), 0, file_display_name);
1479 HeapFree(GetProcessHeap(), 0, full_path_name);
1480 return S_OK;
1482 HeapFree(GetProcessHeap(), 0, file_display_name);
1483 HeapFree(GetProcessHeap(), 0, full_path_name);
1484 IMoniker_Release(file_moniker);
1487 return MK_E_CANTOPENFILE;
1491 HRESULT WINAPI FileMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv)
1493 FileMonikerImpl* newFileMoniker;
1494 HRESULT hr;
1496 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1498 *ppv = NULL;
1500 if (pUnk)
1501 return CLASS_E_NOAGGREGATION;
1503 newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
1504 if (!newFileMoniker)
1505 return E_OUTOFMEMORY;
1507 hr = FileMonikerImpl_Construct(newFileMoniker, L"");
1509 if (SUCCEEDED(hr))
1510 hr = IMoniker_QueryInterface(&newFileMoniker->IMoniker_iface, riid, ppv);
1511 if (FAILED(hr))
1512 HeapFree(GetProcessHeap(),0,newFileMoniker);
1514 return hr;