include: Add STORAGE_HOTPLUG_INFO structure.
[wine.git] / dlls / ole32 / filemoniker.c
blob9368212124dff3f5fb763bb8ff16249b72f29d73
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 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "winnls.h"
31 #include "wine/debug.h"
32 #include "objbase.h"
33 #include "moniker.h"
35 #include "compobj_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39 /* filemoniker data structure */
40 typedef struct FileMonikerImpl{
41 IMoniker IMoniker_iface;
42 IROTData IROTData_iface;
43 LONG ref;
44 LPOLESTR filePathName; /* path string identified by this filemoniker */
45 IUnknown *pMarshal; /* custom marshaler */
46 } FileMonikerImpl;
48 static inline FileMonikerImpl *impl_from_IMoniker(IMoniker *iface)
50 return CONTAINING_RECORD(iface, FileMonikerImpl, IMoniker_iface);
53 static inline FileMonikerImpl *impl_from_IROTData(IROTData *iface)
55 return CONTAINING_RECORD(iface, FileMonikerImpl, IROTData_iface);
58 static const IMonikerVtbl VT_FileMonikerImpl;
60 static FileMonikerImpl *unsafe_impl_from_IMoniker(IMoniker *iface)
62 if (iface->lpVtbl != &VT_FileMonikerImpl)
63 return NULL;
64 return CONTAINING_RECORD(iface, FileMonikerImpl, IMoniker_iface);
67 /* Local function used by filemoniker implementation */
68 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
70 /*******************************************************************************
71 * FileMoniker_QueryInterface
73 static HRESULT WINAPI FileMonikerImpl_QueryInterface(IMoniker *iface, REFIID riid, void **ppvObject)
75 FileMonikerImpl *This = impl_from_IMoniker(iface);
77 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppvObject);
79 if (!ppvObject)
80 return E_INVALIDARG;
82 *ppvObject = 0;
84 if (IsEqualIID(&IID_IUnknown, riid) ||
85 IsEqualIID(&IID_IPersist, riid) ||
86 IsEqualIID(&IID_IPersistStream,riid) ||
87 IsEqualIID(&IID_IMoniker, riid) ||
88 IsEqualGUID(&CLSID_FileMoniker, riid))
90 *ppvObject = iface;
92 else if (IsEqualIID(&IID_IROTData, riid))
93 *ppvObject = &This->IROTData_iface;
94 else if (IsEqualIID(&IID_IMarshal, riid))
96 HRESULT hr = S_OK;
97 if (!This->pMarshal)
98 hr = MonikerMarshal_Create(iface, &This->pMarshal);
99 if (hr != S_OK)
100 return hr;
101 return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject);
104 if (!*ppvObject)
105 return E_NOINTERFACE;
107 IMoniker_AddRef(iface);
109 return S_OK;
112 /******************************************************************************
113 * FileMoniker_AddRef
115 static ULONG WINAPI
116 FileMonikerImpl_AddRef(IMoniker* iface)
118 FileMonikerImpl *This = impl_from_IMoniker(iface);
120 TRACE("(%p)\n",iface);
122 return InterlockedIncrement(&This->ref);
125 static ULONG WINAPI FileMonikerImpl_Release(IMoniker* iface)
127 FileMonikerImpl *moniker = impl_from_IMoniker(iface);
128 ULONG ref = InterlockedDecrement(&moniker->ref);
130 TRACE("%p, refcount %lu.\n", iface, ref);
132 if (!ref)
134 if (moniker->pMarshal) IUnknown_Release(moniker->pMarshal);
135 free(moniker->filePathName);
136 free(moniker);
139 return ref;
142 /******************************************************************************
143 * FileMoniker_GetClassID
145 static HRESULT WINAPI
146 FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID)
148 TRACE("(%p,%p)\n",iface,pClassID);
150 if (pClassID==NULL)
151 return E_POINTER;
153 *pClassID = CLSID_FileMoniker;
155 return S_OK;
158 /******************************************************************************
159 * FileMoniker_IsDirty
161 * Note that the OLE-provided implementations of the IPersistStream::IsDirty
162 * method in the OLE-provided moniker interfaces always return S_FALSE because
163 * their internal state never changes.
165 static HRESULT WINAPI
166 FileMonikerImpl_IsDirty(IMoniker* iface)
169 TRACE("(%p)\n",iface);
171 return S_FALSE;
174 /******************************************************************************
175 * FileMoniker_Load
177 * this function locates and reads from the stream the filePath string
178 * written by FileMonikerImpl_Save
180 static HRESULT WINAPI
181 FileMonikerImpl_Load(IMoniker* iface, IStream* pStm)
183 FileMonikerImpl *This = impl_from_IMoniker(iface);
184 HRESULT res;
185 CHAR* filePathA = NULL;
186 WCHAR* filePathW = NULL;
187 ULONG bread;
188 WORD wbuffer;
189 DWORD dwbuffer, bytesA, bytesW, len;
190 int i;
193 TRACE("(%p,%p)\n",iface,pStm);
195 /* first WORD */
196 res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
197 if (bread!=sizeof(WORD))
199 WARN("Couldn't read 0 word\n");
200 goto fail;
203 /* read filePath string length (plus one) */
204 res=IStream_Read(pStm,&bytesA,sizeof(DWORD),&bread);
205 if (bread != sizeof(DWORD))
207 WARN("Couldn't read file string length\n");
208 goto fail;
211 /* read filePath string */
212 filePathA = malloc(bytesA);
213 if (!filePathA)
215 res = E_OUTOFMEMORY;
216 goto fail;
219 res=IStream_Read(pStm,filePathA,bytesA,&bread);
220 if (bread != bytesA)
222 WARN("Couldn't read file path string\n");
223 goto fail;
226 /* read the unknown value */
227 IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
228 if (bread != sizeof(WORD))
230 WARN("Couldn't read unknown value\n");
231 goto fail;
234 /* read the DEAD constant */
235 IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
236 if (bread != sizeof(WORD))
238 WARN("Couldn't read DEAD constant\n");
239 goto fail;
242 for(i=0;i<5;i++)
244 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
245 if (bread!=sizeof(DWORD))
247 WARN("Couldn't read 0 padding\n");
248 goto fail;
252 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
253 if (bread!=sizeof(DWORD))
254 goto fail;
256 if (!dwbuffer) /* No W-string */
258 bytesA--;
259 len=MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, bytesA, NULL, 0);
260 if (!len)
261 goto fail;
263 filePathW = malloc((len + 1) * sizeof(WCHAR));
264 if (!filePathW)
266 res = E_OUTOFMEMORY;
267 goto fail;
269 MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, -1, filePathW, len+1);
270 goto succeed;
273 if (dwbuffer < 6)
274 goto fail;
276 bytesW=dwbuffer - 6;
278 res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
279 if (bread!=sizeof(DWORD) || dwbuffer!=bytesW)
280 goto fail;
282 res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
283 if (bread!=sizeof(WORD) || wbuffer!=0x3)
284 goto fail;
286 len=bytesW/sizeof(WCHAR);
287 filePathW = malloc((len + 1) * sizeof(WCHAR));
288 if(!filePathW)
290 res = E_OUTOFMEMORY;
291 goto fail;
293 res=IStream_Read(pStm,filePathW,bytesW,&bread);
294 if (bread!=bytesW)
295 goto fail;
297 filePathW[len]=0;
299 succeed:
300 free(filePathA);
301 free(This->filePathName);
302 This->filePathName=filePathW;
304 return S_OK;
306 fail:
307 free(filePathA);
308 free(filePathW);
310 if (SUCCEEDED(res))
311 res = E_FAIL;
312 return res;
315 /******************************************************************************
316 * FileMoniker_Save
318 * This function saves data of this object. In the beginning I thought
319 * that I have just to write the filePath string on Stream. But, when I
320 * tested this function with windows program samples, I noticed that it
321 * was not the case. This implementation is based on XP SP2. Other versions
322 * of Windows have minor variations.
324 * Data which must be written on stream is:
325 * 1) WORD constant: zero (not validated by Windows)
326 * 2) length of the path string ("\0" included)
327 * 3) path string type A
328 * 4) Unknown WORD value: Frequently 0xFFFF, but not always. If set very large,
329 * Windows returns E_OUTOFMEMORY
330 * 5) WORD Constant: 0xDEAD (not validated by Windows)
331 * 6) five DWORD constant: zero (not validated by Windows)
332 * 7) If we're only writing the multibyte version,
333 * write a zero DWORD and finish.
335 * 8) DWORD: double-length of the path string type W ("\0" not
336 * included)
337 * 9) WORD constant: 0x3
338 * 10) filePath unicode string.
341 static HRESULT WINAPI
342 FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
344 FileMonikerImpl *This = impl_from_IMoniker(iface);
345 HRESULT res;
346 LPOLESTR filePathW=This->filePathName;
347 CHAR* filePathA;
348 DWORD bytesA, bytesW, len;
350 static const WORD FFFF = 0xFFFF; /* Constants */
351 static const WORD DEAD = 0xDEAD;
352 static const DWORD ZERO = 0;
353 static const WORD THREE = 0x3;
355 int i;
356 BOOL bUsedDefault, bWriteWide;
358 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
360 if (pStm==NULL)
361 return E_POINTER;
363 /* write a 0 WORD */
364 res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
365 if (FAILED(res)) return res;
367 /* write length of filePath string ( 0 included )*/
368 bytesA = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
369 res=IStream_Write(pStm,&bytesA,sizeof(DWORD),NULL);
370 if (FAILED(res)) return res;
372 /* write A string (with '\0') */
373 filePathA = malloc(bytesA);
374 if (!filePathA)
375 return E_OUTOFMEMORY;
376 WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, bytesA, NULL, &bUsedDefault);
377 res=IStream_Write(pStm,filePathA,bytesA,NULL);
378 free(filePathA);
379 if (FAILED(res)) return res;
381 /* write a WORD 0xFFFF */
382 res=IStream_Write(pStm,&FFFF,sizeof(WORD),NULL);
383 if (FAILED(res)) return res;
385 /* write a WORD 0xDEAD */
386 res=IStream_Write(pStm,&DEAD,sizeof(WORD),NULL);
387 if (FAILED(res)) return res;
389 /* write 5 zero DWORDs */
390 for(i=0;i<5;i++)
392 res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
393 if (FAILED(res)) return res;
396 /* Write the wide version if:
397 * + couldn't convert to CP_ACP,
398 * or + it's a directory,
399 * or + there's a character > 0xFF
401 len = lstrlenW(filePathW);
402 bWriteWide = (bUsedDefault || (len > 0 && filePathW[len-1]=='\\' ));
403 if (!bWriteWide)
405 WCHAR* pch;
406 for(pch=filePathW;*pch;++pch)
408 if (*pch > 0xFF)
410 bWriteWide = TRUE;
411 break;
416 if (!bWriteWide)
417 return IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
419 /* write bytes needed for the filepathW (without 0) + 6 */
420 bytesW = len*sizeof(WCHAR) + 6;
421 res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
422 if (FAILED(res)) return res;
424 /* try again, without the extra 6 */
425 bytesW -= 6;
426 res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
427 if (FAILED(res)) return res;
429 /* write a WORD 3 */
430 res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
431 if (FAILED(res)) return res;
433 /* write W string (no 0) */
434 return IStream_Write(pStm,filePathW,bytesW,NULL);
437 /******************************************************************************
438 * FileMoniker_GetSizeMax
440 static HRESULT WINAPI
441 FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
443 FileMonikerImpl *This = impl_from_IMoniker(iface);
445 TRACE("(%p,%p)\n",iface,pcbSize);
447 if (!pcbSize)
448 return E_POINTER;
450 /* We could calculate exactly (see ...::Save()) but instead
451 * we'll make a quick over-estimate, like Windows (NT4, XP) does.
453 pcbSize->u.LowPart = 0x38 + 4 * lstrlenW(This->filePathName);
454 pcbSize->u.HighPart = 0;
456 return S_OK;
459 /******************************************************************************
460 * FileMoniker_BindToObject
462 static HRESULT WINAPI
463 FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
464 REFIID riid, VOID** ppvResult)
466 FileMonikerImpl *This = impl_from_IMoniker(iface);
467 HRESULT res=E_FAIL;
468 CLSID clsID;
469 IUnknown* pObj=0;
470 IRunningObjectTable *prot=0;
471 IPersistFile *ppf=0;
472 IClassFactory *pcf=0;
473 IClassActivator *pca=0;
475 *ppvResult=0;
477 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
479 if(pmkToLeft==NULL){
481 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
483 if (SUCCEEDED(res)){
484 /* if the requested class was loaded before ! we don't need to reload it */
485 res = IRunningObjectTable_GetObject(prot,iface,&pObj);
487 if (res != S_OK){
488 /* first activation of this class */
489 res=GetClassFile(This->filePathName,&clsID);
490 if (SUCCEEDED(res)){
492 res=CoCreateInstance(&clsID,NULL,CLSCTX_SERVER,&IID_IPersistFile,(void**)&ppf);
493 if (SUCCEEDED(res)){
495 res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
496 if (SUCCEEDED(res)){
498 pObj=(IUnknown*)ppf;
499 IUnknown_AddRef(pObj);
506 else{
507 res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf);
509 if (res==E_NOINTERFACE){
511 res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
513 if (res==E_NOINTERFACE)
514 return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
516 if (pcf!=NULL){
518 IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)&ppf);
520 res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
522 if (SUCCEEDED(res)){
524 pObj=(IUnknown*)ppf;
525 IUnknown_AddRef(pObj);
528 if (pca!=NULL){
530 FIXME("()\n");
532 /*res=GetClassFile(This->filePathName,&clsID);
534 if (SUCCEEDED(res)){
536 res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf);
538 if (SUCCEEDED(res)){
540 pObj=(IUnknown*)ppf;
541 IUnknown_AddRef(pObj);
547 if (pObj!=NULL){
548 /* get the requested interface from the loaded class */
549 res= IUnknown_QueryInterface(pObj,riid,ppvResult);
551 IBindCtx_RegisterObjectBound(pbc,*ppvResult);
553 IUnknown_Release(pObj);
556 if (prot!=NULL)
557 IRunningObjectTable_Release(prot);
559 if (ppf!=NULL)
560 IPersistFile_Release(ppf);
562 if (pca!=NULL)
563 IClassActivator_Release(pca);
565 if (pcf!=NULL)
566 IClassFactory_Release(pcf);
568 return res;
571 /******************************************************************************
572 * FileMoniker_BindToStorage
574 static HRESULT WINAPI
575 FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
576 REFIID riid, void **object)
578 FileMonikerImpl *moniker = impl_from_IMoniker(iface);
579 BIND_OPTS bind_opts;
580 HRESULT hr;
582 TRACE("(%p,%p,%p,%s,%p)\n", iface, pbc, pmkToLeft, debugstr_guid(riid), object);
584 if (!pbc)
585 return E_INVALIDARG;
587 bind_opts.cbStruct = sizeof(bind_opts);
588 hr = IBindCtx_GetBindOptions(pbc, &bind_opts);
589 if (FAILED(hr))
590 return hr;
592 if (!pmkToLeft)
594 if (IsEqualIID(&IID_IStorage, riid))
596 return StgOpenStorage(moniker->filePathName, NULL, bind_opts.grfMode, NULL, 0, (IStorage **)object);
598 else if ((IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)))
599 return E_FAIL;
600 else
601 return E_NOINTERFACE;
604 FIXME("(%p,%p,%p,%s,%p)\n", iface, pbc, pmkToLeft, debugstr_guid(riid), object);
606 return E_NOTIMPL;
609 static HRESULT WINAPI FileMonikerImpl_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD howfar,
610 IMoniker **toleft, IMoniker **reduced)
612 TRACE("%p, %p, %ld, %p, %p.\n", iface, pbc, howfar, toleft, reduced);
614 if (!pbc || !reduced)
615 return E_INVALIDARG;
617 IMoniker_AddRef(iface);
618 *reduced = iface;
620 return MK_S_REDUCED_TO_SELF;
623 static void free_stringtable(LPOLESTR *stringTable)
625 int i;
627 for (i=0; stringTable[i]!=NULL; i++)
628 CoTaskMemFree(stringTable[i]);
629 CoTaskMemFree(stringTable);
632 static int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable)
634 LPOLESTR word;
635 int i=0,j,tabIndex=0, ret=0;
636 LPOLESTR *strgtable ;
638 int len=lstrlenW(str);
640 TRACE("%s, %p\n", debugstr_w(str), *stringTable);
642 strgtable = CoTaskMemAlloc((len + 1)*sizeof(*strgtable));
644 if (strgtable==NULL)
645 return E_OUTOFMEMORY;
647 word = CoTaskMemAlloc((len + 1)*sizeof(WCHAR));
649 if (word==NULL)
651 ret = E_OUTOFMEMORY;
652 goto lend;
655 while(str[i]!=0){
657 if (str[i] == L'\\')
660 strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR));
662 if (strgtable[tabIndex]==NULL)
664 ret = E_OUTOFMEMORY;
665 goto lend;
668 lstrcpyW(strgtable[tabIndex++], L"\\");
670 i++;
673 else {
675 for (j = 0; str[i] && str[i] != L'\\'; i++, j++)
676 word[j]=str[i];
678 word[j]=0;
680 strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1));
682 if (strgtable[tabIndex]==NULL)
684 ret = E_OUTOFMEMORY;
685 goto lend;
688 lstrcpyW(strgtable[tabIndex++],word);
691 strgtable[tabIndex]=NULL;
693 *stringTable=strgtable;
695 ret = tabIndex;
697 lend:
698 if (ret < 0)
700 for (i = 0; i < tabIndex; i++)
701 CoTaskMemFree(strgtable[i]);
703 CoTaskMemFree(strgtable);
706 CoTaskMemFree(word);
708 return ret;
711 /******************************************************************************
712 * FileMoniker_ComposeWith
714 static HRESULT WINAPI
715 FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
716 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
718 HRESULT res;
719 LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0;
720 IBindCtx *bind=0;
721 int i=0,j=0,lastIdx1=0,lastIdx2=0;
722 DWORD mkSys, order;
724 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
726 if (ppmkComposite==NULL)
727 return E_POINTER;
729 if (pmkRight==NULL)
730 return E_INVALIDARG;
732 *ppmkComposite=0;
734 IMoniker_IsSystemMoniker(pmkRight,&mkSys);
736 /* check if we have two FileMonikers to compose or not */
737 if(mkSys==MKSYS_FILEMONIKER){
739 CreateBindCtx(0,&bind);
741 IMoniker_GetDisplayName(iface,bind,NULL,&str1);
742 IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2);
744 /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */
745 lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1;
746 lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1;
748 if ((lastIdx1 == -1 && lastIdx2 > -1) || (lastIdx1 == 1 && !wcscmp(strDec1[0], L"..")))
749 res = MK_E_SYNTAX;
750 else{
751 if (!wcscmp(strDec1[lastIdx1], L"\\"))
752 lastIdx1--;
754 /* for each "..\" in the left of str2 remove the right element from str1 */
755 for (i = 0; lastIdx1 >= 0 && strDec2[i] && !wcscmp(strDec2[i], L".."); i += 2)
756 lastIdx1-=2;
758 /* the length of the composed path string is increased by the sum of the two paths' lengths */
759 newStr = malloc(sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1));
761 if (newStr){
762 /* new path is the concatenation of the rest of str1 and str2 */
763 for(*newStr=0,j=0;j<=lastIdx1;j++)
764 lstrcatW(newStr,strDec1[j]);
766 if ((!strDec2[i] && lastIdx1 > -1 && lastIdx2 > -1) || wcscmp(strDec2[i], L"\\"))
767 lstrcatW(newStr, L"\\");
769 for(j=i;j<=lastIdx2;j++)
770 lstrcatW(newStr,strDec2[j]);
772 /* create a new moniker with the new string */
773 res=CreateFileMoniker(newStr,ppmkComposite);
775 free(newStr);
777 else res = E_OUTOFMEMORY;
780 free_stringtable(strDec1);
781 free_stringtable(strDec2);
783 CoTaskMemFree(str1);
784 CoTaskMemFree(str2);
786 return res;
788 else if (is_anti_moniker(pmkRight, &order))
790 return order > 1 ? create_anti_moniker(order - 1, ppmkComposite) : S_OK;
792 else if (fOnlyIfNotGeneric){
794 *ppmkComposite=NULL;
795 return MK_E_NEEDGENERIC;
797 else
799 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
802 /******************************************************************************
803 * FileMoniker_Enum
805 static HRESULT WINAPI
806 FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
808 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
810 if (ppenumMoniker == NULL)
811 return E_POINTER;
813 *ppenumMoniker = NULL;
815 return S_OK;
818 static HRESULT WINAPI FileMonikerImpl_IsEqual(IMoniker *iface, IMoniker *other)
820 FileMonikerImpl *moniker = impl_from_IMoniker(iface), *other_moniker;
822 TRACE("%p, %p.\n", iface, other);
824 if (!other)
825 return E_INVALIDARG;
827 other_moniker = unsafe_impl_from_IMoniker(other);
828 if (!other_moniker)
829 return S_FALSE;
831 return !wcsicmp(moniker->filePathName, other_moniker->filePathName) ? S_OK : S_FALSE;
834 /******************************************************************************
835 * FileMoniker_Hash
837 static HRESULT WINAPI
838 FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
840 FileMonikerImpl *This = impl_from_IMoniker(iface);
841 int h = 0,i,skip,len;
842 int off = 0;
843 LPOLESTR val;
845 if (pdwHash==NULL)
846 return E_POINTER;
848 val = This->filePathName;
849 len = lstrlenW(val);
851 if (len < 16) {
852 for (i = len ; i > 0; i--) {
853 h = (h * 37) + val[off++];
855 } else {
856 /* only sample some characters */
857 skip = len / 8;
858 for (i = len ; i > 0; i -= skip, off += skip) {
859 h = (h * 39) + val[off];
863 *pdwHash=h;
865 return S_OK;
868 /******************************************************************************
869 * FileMoniker_IsRunning
871 static HRESULT WINAPI
872 FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
873 IMoniker* pmkNewlyRunning)
875 IRunningObjectTable* rot;
876 HRESULT res;
878 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
880 if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) )
881 return S_OK;
883 if (pbc==NULL)
884 return E_POINTER;
886 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
888 if (FAILED(res))
889 return res;
891 res = IRunningObjectTable_IsRunning(rot,iface);
893 IRunningObjectTable_Release(rot);
895 return res;
898 /******************************************************************************
899 * FileMoniker_GetTimeOfLastChange
900 ******************************************************************************/
901 static HRESULT WINAPI
902 FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
903 IMoniker* pmkToLeft, FILETIME* pFileTime)
905 FileMonikerImpl *This = impl_from_IMoniker(iface);
906 IRunningObjectTable* rot;
907 HRESULT res;
908 WIN32_FILE_ATTRIBUTE_DATA info;
910 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime);
912 if (pFileTime==NULL)
913 return E_POINTER;
915 if (pmkToLeft!=NULL)
916 return E_INVALIDARG;
918 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
920 if (FAILED(res))
921 return res;
923 res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime);
925 if (FAILED(res)){ /* the moniker is not registered */
927 if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info))
928 return MK_E_NOOBJECT;
930 *pFileTime=info.ftLastWriteTime;
933 return S_OK;
936 /******************************************************************************
937 * FileMoniker_Inverse
939 static HRESULT WINAPI
940 FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
942 TRACE("(%p,%p)\n",iface,ppmk);
944 return CreateAntiMoniker(ppmk);
947 /******************************************************************************
948 * FileMoniker_CommonPrefixWith
950 static HRESULT WINAPI
951 FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
954 LPOLESTR pathThis = NULL, pathOther = NULL, *stringTable1 = NULL;
955 LPOLESTR *stringTable2 = NULL, commonPath = NULL;
956 IBindCtx *bindctx;
957 DWORD mkSys;
958 ULONG nb1,nb2,i,sameIdx;
959 BOOL machineNameCase = FALSE;
960 HRESULT ret;
962 if (ppmkPrefix==NULL)
963 return E_POINTER;
965 if (pmkOther==NULL)
966 return E_INVALIDARG;
968 *ppmkPrefix=0;
970 /* check if we have the same type of moniker */
971 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
972 if (mkSys != MKSYS_FILEMONIKER)
973 return MonikerCommonPrefixWith(iface, pmkOther, ppmkPrefix);
975 ret = CreateBindCtx(0, &bindctx);
976 if (FAILED(ret))
977 return ret;
979 /* create a string based on common part of the two paths */
980 ret = IMoniker_GetDisplayName(iface, bindctx, NULL, &pathThis);
981 if (FAILED(ret))
982 goto failed;
984 ret = IMoniker_GetDisplayName(pmkOther, bindctx, NULL, &pathOther);
985 if (FAILED(ret))
986 goto failed;
988 nb1 = FileMonikerImpl_DecomposePath(pathThis, &stringTable1);
989 if (FAILED(nb1)) {
990 ret = nb1;
991 goto failed;
994 nb2 = FileMonikerImpl_DecomposePath(pathOther, &stringTable2);
995 if (FAILED(nb2)) {
996 ret = nb2;
997 goto failed;
1000 if (nb1 == 0 || nb2 == 0) {
1001 ret = MK_E_NOPREFIX;
1002 goto failed;
1005 commonPath = CoTaskMemAlloc(sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1));
1006 if (!commonPath) {
1007 ret = E_OUTOFMEMORY;
1008 goto failed;
1011 *commonPath = 0;
1012 for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) &&
1013 (stringTable2[sameIdx]!=NULL) &&
1014 (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++);
1016 if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){
1017 machineNameCase = TRUE;
1019 for(i=2;i<sameIdx;i++)
1020 if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){
1021 machineNameCase = FALSE;
1022 break;
1026 if (machineNameCase && *stringTable1[sameIdx-1]=='\\')
1027 sameIdx--;
1029 if (machineNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
1030 ret = MK_E_NOPREFIX;
1031 else
1033 for (i = 0; i < sameIdx; i++)
1034 lstrcatW(commonPath,stringTable1[i]);
1035 ret = CreateFileMoniker(commonPath, ppmkPrefix);
1038 failed:
1039 IBindCtx_Release(bindctx);
1040 CoTaskMemFree(pathThis);
1041 CoTaskMemFree(pathOther);
1042 CoTaskMemFree(commonPath);
1043 if (stringTable1) free_stringtable(stringTable1);
1044 if (stringTable2) free_stringtable(stringTable2);
1046 return ret;
1049 /******************************************************************************
1050 * FileMoniker_RelativePathTo
1052 static HRESULT WINAPI
1053 FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
1055 IBindCtx *bind;
1056 HRESULT res;
1057 LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
1058 DWORD len1=0,len2=0,sameIdx=0,j=0;
1060 TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
1062 if (ppmkRelPath==NULL)
1063 return E_POINTER;
1065 if (pmOther==NULL)
1066 return E_INVALIDARG;
1068 res=CreateBindCtx(0,&bind);
1069 if (FAILED(res))
1070 return res;
1072 res=IMoniker_GetDisplayName(iface,bind,NULL,&str1);
1073 if (FAILED(res))
1074 return res;
1075 res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2);
1076 if (FAILED(res))
1077 return res;
1079 len1=FileMonikerImpl_DecomposePath(str1,&tabStr1);
1080 if (FAILED(len1))
1081 return E_OUTOFMEMORY;
1082 len2=FileMonikerImpl_DecomposePath(str2,&tabStr2);
1084 if (FAILED(len2))
1086 free_stringtable(tabStr1);
1087 return E_OUTOFMEMORY;
1090 /* count the number of similar items from the begin of the two paths */
1091 for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) &&
1092 (tabStr2[sameIdx]!=NULL) &&
1093 (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++);
1095 /* begin the construction of relativePath */
1096 /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */
1097 /* by "..\\" in the begin */
1098 relPath = malloc(sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2)));
1100 *relPath=0;
1102 if (len2>0 && !(len1==1 && len2==1 && sameIdx==0))
1103 for(j=sameIdx;(tabStr1[j] != NULL); j++)
1104 if (*tabStr1[j]!='\\')
1105 lstrcatW(relPath, L"..\\");
1107 /* add items of the second path (similar items with the first path are not included) to the relativePath */
1108 for(j=sameIdx;tabStr2[j]!=NULL;j++)
1109 lstrcatW(relPath,tabStr2[j]);
1111 res=CreateFileMoniker(relPath,ppmkRelPath);
1113 free_stringtable(tabStr1);
1114 free_stringtable(tabStr2);
1115 CoTaskMemFree(str1);
1116 CoTaskMemFree(str2);
1117 free(relPath);
1119 if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0))
1120 return MK_S_HIM;
1122 return res;
1125 /******************************************************************************
1126 * FileMoniker_GetDisplayName
1128 static HRESULT WINAPI
1129 FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1130 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1132 FileMonikerImpl *This = impl_from_IMoniker(iface);
1133 int len=lstrlenW(This->filePathName);
1135 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1137 if (ppszDisplayName==NULL)
1138 return E_POINTER;
1140 if (pmkToLeft!=NULL)
1141 return E_INVALIDARG;
1143 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
1144 if (*ppszDisplayName==NULL)
1145 return E_OUTOFMEMORY;
1147 lstrcpyW(*ppszDisplayName,This->filePathName);
1149 TRACE("-- %s\n", debugstr_w(*ppszDisplayName));
1151 return S_OK;
1154 /******************************************************************************
1155 * FileMoniker_ParseDisplayName
1157 static HRESULT WINAPI
1158 FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
1159 LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
1161 FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
1162 return E_NOTIMPL;
1165 /******************************************************************************
1166 * FileMoniker_IsSystemMoniker
1168 static HRESULT WINAPI
1169 FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1171 TRACE("(%p,%p)\n",iface,pwdMksys);
1173 if (!pwdMksys)
1174 return E_POINTER;
1176 (*pwdMksys)=MKSYS_FILEMONIKER;
1178 return S_OK;
1181 /*******************************************************************************
1182 * FileMonikerIROTData_QueryInterface
1184 static HRESULT WINAPI
1185 FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
1188 FileMonikerImpl *This = impl_from_IROTData(iface);
1190 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1192 return FileMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
1195 /***********************************************************************
1196 * FileMonikerIROTData_AddRef
1198 static ULONG WINAPI
1199 FileMonikerROTDataImpl_AddRef(IROTData *iface)
1201 FileMonikerImpl *This = impl_from_IROTData(iface);
1203 TRACE("(%p)\n",This);
1205 return IMoniker_AddRef(&This->IMoniker_iface);
1208 /***********************************************************************
1209 * FileMonikerIROTData_Release
1211 static ULONG WINAPI
1212 FileMonikerROTDataImpl_Release(IROTData* iface)
1214 FileMonikerImpl *This = impl_from_IROTData(iface);
1216 TRACE("(%p)\n",This);
1218 return FileMonikerImpl_Release(&This->IMoniker_iface);
1221 /******************************************************************************
1222 * FileMonikerIROTData_GetComparisonData
1224 static HRESULT WINAPI
1225 FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData,
1226 ULONG cbMax, ULONG* pcbData)
1228 FileMonikerImpl *This = impl_from_IROTData(iface);
1229 int len = lstrlenW(This->filePathName)+1;
1230 int i;
1231 LPWSTR pszFileName;
1233 TRACE("%p, %p, %lu, %p.\n", iface, pbData, cbMax, pcbData);
1235 *pcbData = sizeof(CLSID) + len * sizeof(WCHAR);
1236 if (cbMax < *pcbData)
1237 return E_OUTOFMEMORY;
1239 memcpy(pbData, &CLSID_FileMoniker, sizeof(CLSID));
1240 pszFileName = (LPWSTR)(pbData+sizeof(CLSID));
1241 for (i = 0; i < len; i++)
1242 pszFileName[i] = towupper(This->filePathName[i]);
1244 return S_OK;
1248 * Virtual function table for the FileMonikerImpl class which include IPersist,
1249 * IPersistStream and IMoniker functions.
1251 static const IMonikerVtbl VT_FileMonikerImpl =
1253 FileMonikerImpl_QueryInterface,
1254 FileMonikerImpl_AddRef,
1255 FileMonikerImpl_Release,
1256 FileMonikerImpl_GetClassID,
1257 FileMonikerImpl_IsDirty,
1258 FileMonikerImpl_Load,
1259 FileMonikerImpl_Save,
1260 FileMonikerImpl_GetSizeMax,
1261 FileMonikerImpl_BindToObject,
1262 FileMonikerImpl_BindToStorage,
1263 FileMonikerImpl_Reduce,
1264 FileMonikerImpl_ComposeWith,
1265 FileMonikerImpl_Enum,
1266 FileMonikerImpl_IsEqual,
1267 FileMonikerImpl_Hash,
1268 FileMonikerImpl_IsRunning,
1269 FileMonikerImpl_GetTimeOfLastChange,
1270 FileMonikerImpl_Inverse,
1271 FileMonikerImpl_CommonPrefixWith,
1272 FileMonikerImpl_RelativePathTo,
1273 FileMonikerImpl_GetDisplayName,
1274 FileMonikerImpl_ParseDisplayName,
1275 FileMonikerImpl_IsSystemMoniker
1278 /* Virtual function table for the IROTData class. */
1279 static const IROTDataVtbl VT_ROTDataImpl =
1281 FileMonikerROTDataImpl_QueryInterface,
1282 FileMonikerROTDataImpl_AddRef,
1283 FileMonikerROTDataImpl_Release,
1284 FileMonikerROTDataImpl_GetComparisonData
1287 /******************************************************************************
1288 * FileMoniker_Construct (local function)
1290 static HRESULT FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
1292 int nb=0,i;
1293 int sizeStr=lstrlenW(lpszPathName);
1294 LPOLESTR *tabStr=0;
1295 BOOL addBkSlash;
1297 TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName));
1299 /* Initialize the virtual function table. */
1300 This->IMoniker_iface.lpVtbl = &VT_FileMonikerImpl;
1301 This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1302 This->ref = 0;
1303 This->pMarshal = NULL;
1305 This->filePathName = malloc(sizeof(WCHAR)*(sizeStr+1));
1307 if (This->filePathName==NULL)
1308 return E_OUTOFMEMORY;
1310 lstrcpyW(This->filePathName,lpszPathName);
1312 nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr);
1314 if (nb > 0 ){
1316 addBkSlash = TRUE;
1317 if (wcscmp(tabStr[0], L".."))
1318 addBkSlash = FALSE;
1319 else
1320 for(i=0;i<nb;i++){
1322 if (wcscmp(tabStr[i], L"..") && wcscmp(tabStr[i], L"\\"))
1324 addBkSlash = FALSE;
1325 break;
1327 else
1329 if (!wcscmp(tabStr[i], L"\\") && i < nb - 1 && !wcscmp(tabStr[i+1], L"\\"))
1331 *tabStr[i]=0;
1332 sizeStr--;
1333 addBkSlash = FALSE;
1334 break;
1338 if (!wcscmp(tabStr[nb-1], L"\\"))
1339 addBkSlash = FALSE;
1341 This->filePathName = realloc(This->filePathName, (sizeStr+1)*sizeof(WCHAR));
1343 *This->filePathName=0;
1345 for(i=0;tabStr[i]!=NULL;i++)
1346 lstrcatW(This->filePathName,tabStr[i]);
1348 if (addBkSlash)
1349 lstrcatW(This->filePathName, L"\\");
1352 free_stringtable(tabStr);
1354 return S_OK;
1357 /******************************************************************************
1358 * CreateFileMoniker (OLE32.@)
1359 ******************************************************************************/
1360 HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, IMoniker **ppmk)
1362 FileMonikerImpl *moniker;
1363 HRESULT hr;
1365 TRACE("%s, %p.\n", debugstr_w(lpszPathName), ppmk);
1367 if (!ppmk)
1368 return E_POINTER;
1370 if(!lpszPathName)
1371 return MK_E_SYNTAX;
1373 *ppmk=NULL;
1375 if (!(moniker = calloc(1, sizeof(*moniker))))
1376 return E_OUTOFMEMORY;
1378 hr = FileMonikerImpl_Construct(moniker, lpszPathName);
1380 if (SUCCEEDED(hr))
1381 hr = IMoniker_QueryInterface(&moniker->IMoniker_iface, &IID_IMoniker, (void **)ppmk);
1382 else
1383 free(moniker);
1385 return hr;
1388 /* find a character from a set in reverse without the string having to be null-terminated */
1389 static inline WCHAR *memrpbrkW(const WCHAR *ptr, size_t n, const WCHAR *accept)
1391 const WCHAR *end, *ret = NULL;
1392 for (end = ptr + n; ptr < end; ptr++) if (wcschr(accept, *ptr)) ret = ptr;
1393 return (WCHAR *)ret;
1396 HRESULT FileMoniker_CreateFromDisplayName(LPBC pbc, LPCOLESTR szDisplayName,
1397 LPDWORD pchEaten, IMoniker **ppmk)
1399 LPCWSTR end;
1401 for (end = szDisplayName + lstrlenW(szDisplayName);
1402 end && (end != szDisplayName);
1403 end = memrpbrkW(szDisplayName, end - szDisplayName, L":\\/!"))
1405 HRESULT hr;
1406 IRunningObjectTable *rot;
1407 IMoniker *file_moniker;
1408 LPWSTR file_display_name;
1409 LPWSTR full_path_name;
1410 DWORD full_path_name_len;
1411 int len = end - szDisplayName;
1413 file_display_name = malloc((len + 1) * sizeof(WCHAR));
1414 if (!file_display_name) return E_OUTOFMEMORY;
1415 memcpy(file_display_name, szDisplayName, len * sizeof(WCHAR));
1416 file_display_name[len] = '\0';
1418 hr = CreateFileMoniker(file_display_name, &file_moniker);
1419 if (FAILED(hr))
1421 free(file_display_name);
1422 return hr;
1425 hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
1426 if (FAILED(hr))
1428 free(file_display_name);
1429 IMoniker_Release(file_moniker);
1430 return hr;
1433 hr = IRunningObjectTable_IsRunning(rot, file_moniker);
1434 IRunningObjectTable_Release(rot);
1435 if (FAILED(hr))
1437 free(file_display_name);
1438 IMoniker_Release(file_moniker);
1439 return hr;
1441 if (hr == S_OK)
1443 TRACE("found running file moniker for %s\n", debugstr_w(file_display_name));
1444 *pchEaten = len;
1445 *ppmk = file_moniker;
1446 free(file_display_name);
1447 return S_OK;
1450 full_path_name_len = GetFullPathNameW(file_display_name, 0, NULL, NULL);
1451 if (!full_path_name_len)
1453 free(file_display_name);
1454 IMoniker_Release(file_moniker);
1455 return MK_E_SYNTAX;
1457 full_path_name = malloc(full_path_name_len * sizeof(WCHAR));
1458 if (!full_path_name)
1460 free(file_display_name);
1461 IMoniker_Release(file_moniker);
1462 return E_OUTOFMEMORY;
1464 GetFullPathNameW(file_display_name, full_path_name_len, full_path_name, NULL);
1466 if (GetFileAttributesW(full_path_name) == INVALID_FILE_ATTRIBUTES)
1467 TRACE("couldn't open file %s\n", debugstr_w(full_path_name));
1468 else
1470 TRACE("got file moniker for %s\n", debugstr_w(szDisplayName));
1471 *pchEaten = len;
1472 *ppmk = file_moniker;
1473 free(file_display_name);
1474 free(full_path_name);
1475 return S_OK;
1477 free(file_display_name);
1478 free(full_path_name);
1479 IMoniker_Release(file_moniker);
1482 return MK_E_CANTOPENFILE;
1486 HRESULT WINAPI FileMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv)
1488 FileMonikerImpl* newFileMoniker;
1489 HRESULT hr;
1491 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1493 *ppv = NULL;
1495 if (pUnk)
1496 return CLASS_E_NOAGGREGATION;
1498 newFileMoniker = calloc(1, sizeof(*newFileMoniker));
1499 if (!newFileMoniker)
1500 return E_OUTOFMEMORY;
1502 hr = FileMonikerImpl_Construct(newFileMoniker, L"");
1504 if (SUCCEEDED(hr))
1505 hr = IMoniker_QueryInterface(&newFileMoniker->IMoniker_iface, riid, ppv);
1506 if (FAILED(hr))
1507 free(newFileMoniker);
1509 return hr;