Sweden-Number/dlls/scrrun/filesystem.c

2297 lines
62 KiB
C

/*
* Copyright 2012 Alistair Leslie-Hughes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#include "config.h"
#include <stdarg.h>
#include <limits.h>
#include "windef.h"
#include "winbase.h"
#include "ole2.h"
#include "olectl.h"
#include "dispex.h"
#include "ntsecapi.h"
#include "scrrun.h"
#include "scrrun_private.h"
#include "wine/debug.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
struct enumdata {
union
{
struct
{
IFolderCollection *coll;
HANDLE find;
BSTR path;
} foldercoll;
} u;
};
struct enumvariant {
IEnumVARIANT IEnumVARIANT_iface;
LONG ref;
struct enumdata data;
};
struct foldercollection {
IFolderCollection IFolderCollection_iface;
LONG ref;
BSTR path;
};
struct folder {
IFolder IFolder_iface;
LONG ref;
BSTR path;
};
struct file {
IFile IFile_iface;
LONG ref;
WCHAR *path;
};
struct textstream {
ITextStream ITextStream_iface;
LONG ref;
IOMode mode;
};
enum iotype {
IORead,
IOWrite
};
static inline struct folder *impl_from_IFolder(IFolder *iface)
{
return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
}
static inline struct file *impl_from_IFile(IFile *iface)
{
return CONTAINING_RECORD(iface, struct file, IFile_iface);
}
static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
{
return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
}
static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
{
return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
}
static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
{
return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
}
static inline HRESULT create_error(DWORD err)
{
switch(err) {
case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
default:
FIXME("Unsupported error code: %d\n", err);
return E_FAIL;
}
}
static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
{
if (type == IORead)
return This->mode == ForWriting || This->mode == ForAppending;
else
return TRUE;
}
static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
{
struct textstream *This = impl_from_ITextStream(iface);
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_ITextStream) ||
IsEqualIID(riid, &IID_IDispatch) ||
IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
ITextStream_AddRef(iface);
return S_OK;
}
*obj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI textstream_AddRef(ITextStream *iface)
{
struct textstream *This = impl_from_ITextStream(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
return ref;
}
static ULONG WINAPI textstream_Release(ITextStream *iface)
{
struct textstream *This = impl_from_ITextStream(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
if (!ref)
heap_free(This);
return ref;
}
static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
{
struct textstream *This = impl_from_ITextStream(iface);
TRACE("(%p)->(%p)\n", This, pctinfo);
*pctinfo = 1;
return S_OK;
}
static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
LCID lcid, ITypeInfo **ppTInfo)
{
struct textstream *This = impl_from_ITextStream(iface);
TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
return get_typeinfo(ITextStream_tid, ppTInfo);
}
static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
{
struct textstream *This = impl_from_ITextStream(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
hr = get_typeinfo(ITextStream_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
struct textstream *This = impl_from_ITextStream(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
hr = get_typeinfo(ITextStream_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgErr);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%p): stub\n", This, line);
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%p): stub\n", This, column);
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%p): stub\n", This, eos);
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%p): stub\n", This, eol);
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%p): stub\n", This, text);
if (textstream_check_iomode(This, IORead))
return CTL_E_BADFILEMODE;
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%p): stub\n", This, text);
if (textstream_check_iomode(This, IORead))
return CTL_E_BADFILEMODE;
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%p): stub\n", This, text);
if (textstream_check_iomode(This, IORead))
return CTL_E_BADFILEMODE;
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%d): stub\n", This, lines);
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p)->(%d): stub\n", This, count);
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI textstream_Close(ITextStream *iface)
{
struct textstream *This = impl_from_ITextStream(iface);
FIXME("(%p): stub\n", This);
return E_NOTIMPL;
}
static const ITextStreamVtbl textstreamvtbl = {
textstream_QueryInterface,
textstream_AddRef,
textstream_Release,
textstream_GetTypeInfoCount,
textstream_GetTypeInfo,
textstream_GetIDsOfNames,
textstream_Invoke,
textstream_get_Line,
textstream_get_Column,
textstream_get_AtEndOfStream,
textstream_get_AtEndOfLine,
textstream_Read,
textstream_ReadLine,
textstream_ReadAll,
textstream_Write,
textstream_WriteLine,
textstream_WriteBlankLines,
textstream_Skip,
textstream_SkipLine,
textstream_Close
};
static HRESULT create_textstream(IOMode mode, ITextStream **ret)
{
struct textstream *stream;
stream = heap_alloc(sizeof(struct textstream));
if (!stream) return E_OUTOFMEMORY;
stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
stream->ref = 1;
stream->mode = mode;
*ret = &stream->ITextStream_iface;
return S_OK;
}
static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
{
struct enumvariant *This = impl_from_IEnumVARIANT(iface);
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
*obj = NULL;
if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
IsEqualIID( riid, &IID_IUnknown ))
{
*obj = iface;
IEnumVARIANT_AddRef(iface);
}
else
return E_NOINTERFACE;
return S_OK;
}
static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
{
struct enumvariant *This = impl_from_IEnumVARIANT(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
return ref;
}
static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
{
struct enumvariant *This = impl_from_IEnumVARIANT(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
if (!ref)
{
IFolderCollection_Release(This->data.u.foldercoll.coll);
SysFreeString(This->data.u.foldercoll.path);
FindClose(This->data.u.foldercoll.find);
heap_free(This);
}
return ref;
}
static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
{
struct enumvariant *This = impl_from_IEnumVARIANT(iface);
FIXME("(%p)->(%d %p %p): stub\n", This, celt, var, fetched);
return E_NOTIMPL;
}
static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
{
struct enumvariant *This = impl_from_IEnumVARIANT(iface);
FIXME("(%p)->(%d): stub\n", This, celt);
return E_NOTIMPL;
}
static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
{
struct enumvariant *This = impl_from_IEnumVARIANT(iface);
TRACE("(%p)\n", This);
FindClose(This->data.u.foldercoll.find);
This->data.u.foldercoll.find = NULL;
return S_OK;
}
static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
{
struct enumvariant *This = impl_from_IEnumVARIANT(iface);
FIXME("(%p)->(%p): stub\n", This, pclone);
return E_NOTIMPL;
}
static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
enumvariant_QueryInterface,
enumvariant_AddRef,
foldercoll_enumvariant_Release,
foldercoll_enumvariant_Next,
foldercoll_enumvariant_Skip,
foldercoll_enumvariant_Reset,
foldercoll_enumvariant_Clone
};
static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
{
struct enumvariant *This;
*newenum = NULL;
This = heap_alloc(sizeof(*This));
if (!This) return E_OUTOFMEMORY;
This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
This->ref = 1;
This->data.u.foldercoll.find = NULL;
This->data.u.foldercoll.path = SysAllocString(collection->path);
if (!This->data.u.foldercoll.path)
{
heap_free(This);
return E_OUTOFMEMORY;
}
This->data.u.foldercoll.coll = &collection->IFolderCollection_iface;
IFolderCollection_AddRef(This->data.u.foldercoll.coll);
*newenum = (IUnknown*)&This->IEnumVARIANT_iface;
return S_OK;
}
static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
*obj = NULL;
if (IsEqualIID( riid, &IID_IFolderCollection ) ||
IsEqualIID( riid, &IID_IDispatch ) ||
IsEqualIID( riid, &IID_IUnknown ))
{
*obj = iface;
IFolderCollection_AddRef(iface);
}
else
return E_NOINTERFACE;
return S_OK;
}
static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
return ref;
}
static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
if (!ref)
{
SysFreeString(This->path);
heap_free(This);
}
return ref;
}
static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
TRACE("(%p)->(%p)\n", This, pctinfo);
*pctinfo = 1;
return S_OK;
}
static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
LCID lcid, ITypeInfo **ppTInfo)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
return get_typeinfo(IFolderCollection_tid, ppTInfo);
}
static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgErr);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
return E_NOTIMPL;
}
static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
FIXME("(%p)->(%p): stub\n", This, folder);
return E_NOTIMPL;
}
static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
TRACE("(%p)->(%p)\n", This, newenum);
if(!newenum)
return E_POINTER;
return create_foldercoll_enum(This, newenum);
}
static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
{
struct foldercollection *This = impl_from_IFolderCollection(iface);
static const WCHAR allW[] = {'\\','*',0};
WIN32_FIND_DATAW data;
WCHAR pathW[MAX_PATH];
HANDLE handle;
TRACE("(%p)->(%p)\n", This, count);
if(!count)
return E_POINTER;
*count = 0;
strcpyW(pathW, This->path);
strcatW(pathW, allW);
handle = FindFirstFileW(pathW, &data);
if (handle == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
do
{
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
*count += 1;
} while (FindNextFileW(handle, &data));
FindClose(handle);
return S_OK;
}
static const IFolderCollectionVtbl foldercollvtbl = {
foldercoll_QueryInterface,
foldercoll_AddRef,
foldercoll_Release,
foldercoll_GetTypeInfoCount,
foldercoll_GetTypeInfo,
foldercoll_GetIDsOfNames,
foldercoll_Invoke,
foldercoll_Add,
foldercoll_get_Item,
foldercoll_get__NewEnum,
foldercoll_get_Count
};
static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
{
struct foldercollection *This;
*folders = NULL;
This = heap_alloc(sizeof(struct foldercollection));
if (!This) return E_OUTOFMEMORY;
This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
This->ref = 1;
This->path = SysAllocString(path);
if (!This->path)
{
heap_free(This);
return E_OUTOFMEMORY;
}
*folders = &This->IFolderCollection_iface;
return S_OK;
}
static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
{
struct folder *This = impl_from_IFolder(iface);
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
*obj = NULL;
if (IsEqualIID( riid, &IID_IFolder ) ||
IsEqualIID( riid, &IID_IDispatch ) ||
IsEqualIID( riid, &IID_IUnknown))
{
*obj = iface;
IFolder_AddRef(iface);
}
else
return E_NOINTERFACE;
return S_OK;
}
static ULONG WINAPI folder_AddRef(IFolder *iface)
{
struct folder *This = impl_from_IFolder(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
return ref;
}
static ULONG WINAPI folder_Release(IFolder *iface)
{
struct folder *This = impl_from_IFolder(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p)->(%d)\n", This, ref);
if (!ref)
{
SysFreeString(This->path);
heap_free(This);
}
return ref;
}
static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
{
struct folder *This = impl_from_IFolder(iface);
TRACE("(%p)->(%p)\n", This, pctinfo);
*pctinfo = 1;
return S_OK;
}
static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
LCID lcid, ITypeInfo **ppTInfo)
{
struct folder *This = impl_from_IFolder(iface);
TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
return get_typeinfo(IFolder_tid, ppTInfo);
}
static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
{
struct folder *This = impl_from_IFolder(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
hr = get_typeinfo(IFolder_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
struct folder *This = impl_from_IFolder(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
hr = get_typeinfo(IFolder_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgErr);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, path);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, name);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, path);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, name);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, drive);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, parent);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, attr);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(0x%x): stub\n", This, attr);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, date);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, date);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, date);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, type);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%x): stub\n", This, force);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, isroot);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, size);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
{
struct folder *This = impl_from_IFolder(iface);
TRACE("(%p)->(%p)\n", This, folders);
if(!folders)
return E_POINTER;
return create_foldercoll(This->path, folders);
}
static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%p): stub\n", This, files);
return E_NOTIMPL;
}
static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
VARIANT_BOOL unicode, ITextStream **stream)
{
struct folder *This = impl_from_IFolder(iface);
FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
return E_NOTIMPL;
}
static const IFolderVtbl foldervtbl = {
folder_QueryInterface,
folder_AddRef,
folder_Release,
folder_GetTypeInfoCount,
folder_GetTypeInfo,
folder_GetIDsOfNames,
folder_Invoke,
folder_get_Path,
folder_get_Name,
folder_put_Name,
folder_get_ShortPath,
folder_get_ShortName,
folder_get_Drive,
folder_get_ParentFolder,
folder_get_Attributes,
folder_put_Attributes,
folder_get_DateCreated,
folder_get_DateLastModified,
folder_get_DateLastAccessed,
folder_get_Type,
folder_Delete,
folder_Copy,
folder_Move,
folder_get_IsRootFolder,
folder_get_Size,
folder_get_SubFolders,
folder_get_Files,
folder_CreateTextFile
};
static HRESULT create_folder(BSTR path, IFolder **folder)
{
struct folder *This;
*folder = NULL;
This = heap_alloc(sizeof(struct folder));
if (!This) return E_OUTOFMEMORY;
This->IFolder_iface.lpVtbl = &foldervtbl;
This->ref = 1;
This->path = SysAllocString(path);
if (!This->path)
{
heap_free(This);
return E_OUTOFMEMORY;
}
*folder = &This->IFolder_iface;
return S_OK;
}
static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
{
struct file *This = impl_from_IFile(iface);
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IFile) ||
IsEqualIID(riid, &IID_IDispatch) ||
IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
IFile_AddRef(iface);
return S_OK;
}
*obj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI file_AddRef(IFile *iface)
{
struct file *This = impl_from_IFile(iface);
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI file_Release(IFile *iface)
{
struct file *This = impl_from_IFile(iface);
LONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if(!ref)
heap_free(This->path);
return ref;
}
static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
{
struct file *This = impl_from_IFile(iface);
TRACE("(%p)->(%p)\n", This, pctinfo);
*pctinfo = 1;
return S_OK;
}
static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
struct file *This = impl_from_IFile(iface);
TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
return get_typeinfo(IFile_tid, ppTInfo);
}
static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
struct file *This = impl_from_IFile(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
rgszNames, cNames, lcid, rgDispId);
hr = get_typeinfo(IFile_tid, &typeinfo);
if(SUCCEEDED(hr)) {
hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
struct file *This = impl_from_IFile(iface);
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
hr = get_typeinfo(IFile_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgErr);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *pbstrPath)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pbstrPath);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *pbstrName)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pbstrName);
return E_NOTIMPL;
}
static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pbstrPath);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pbstrName);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, ppdrive);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, ppfolder);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
{
struct file *This = impl_from_IFile(iface);
DWORD fa;
TRACE("(%p)->(%p)\n", This, pfa);
if(!pfa)
return E_POINTER;
fa = GetFileAttributesW(This->path);
if(fa == INVALID_FILE_ATTRIBUTES)
return create_error(GetLastError());
*pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
return S_OK;
}
static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%x)\n", This, pfa);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pdate);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pdate);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pdate);
return E_NOTIMPL;
}
static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
{
struct file *This = impl_from_IFile(iface);
WIN32_FIND_DATAW fd;
HANDLE f;
TRACE("(%p)->(%p)\n", This, pvarSize);
if(!pvarSize)
return E_POINTER;
f = FindFirstFileW(This->path, &fd);
if(f == INVALID_HANDLE_VALUE)
return create_error(GetLastError());
FindClose(f);
if(fd.nFileSizeHigh || fd.nFileSizeLow>INT_MAX) {
V_VT(pvarSize) = VT_R8;
V_R8(pvarSize) = ((ULONGLONG)fd.nFileSizeHigh<<32) + fd.nFileSizeLow;
}else {
V_VT(pvarSize) = VT_I4;
V_I4(pvarSize) = fd.nFileSizeLow;
}
return S_OK;
}
static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%p)\n", This, pbstrType);
return E_NOTIMPL;
}
static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%x)\n", This, Force);
return E_NOTIMPL;
}
static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
return E_NOTIMPL;
}
static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
return E_NOTIMPL;
}
static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode IOMode, Tristate Format, ITextStream **ppts)
{
struct file *This = impl_from_IFile(iface);
FIXME("(%p)->(%x %x %p)\n", This, IOMode, Format, ppts);
return E_NOTIMPL;
}
static const IFileVtbl file_vtbl = {
file_QueryInterface,
file_AddRef,
file_Release,
file_GetTypeInfoCount,
file_GetTypeInfo,
file_GetIDsOfNames,
file_Invoke,
file_get_Path,
file_get_Name,
file_put_Name,
file_get_ShortPath,
file_get_ShortName,
file_get_Drive,
file_get_ParentFolder,
file_get_Attributes,
file_put_Attributes,
file_get_DateCreated,
file_get_DateLastModified,
file_get_DateLastAccessed,
file_get_Size,
file_get_Type,
file_Delete,
file_Copy,
file_Move,
file_OpenAsTextStream
};
static HRESULT create_file(BSTR path, IFile **file)
{
struct file *f;
DWORD len, attrs;
*file = NULL;
f = heap_alloc(sizeof(struct file));
if(!f)
return E_OUTOFMEMORY;
f->IFile_iface.lpVtbl = &file_vtbl;
f->ref = 1;
len = GetFullPathNameW(path, 0, NULL, NULL);
if(!len) {
heap_free(f);
return E_FAIL;
}
f->path = heap_alloc(len*sizeof(WCHAR));
if(!f->path) {
heap_free(f);
return E_OUTOFMEMORY;
}
if(!GetFullPathNameW(path, len, f->path, NULL)) {
heap_free(f->path);
heap_free(f);
return E_FAIL;
}
if(path[len-1]=='/' || path[len-1]=='\\')
path[len-1] = 0;
attrs = GetFileAttributesW(f->path);
if(attrs==INVALID_FILE_ATTRIBUTES ||
(attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
heap_free(f->path);
heap_free(f);
return create_error(GetLastError());
}
*file = &f->IFile_iface;
return S_OK;
}
static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
{
TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
IsEqualGUID( riid, &IID_IFileSystem ) ||
IsEqualGUID( riid, &IID_IDispatch ) ||
IsEqualGUID( riid, &IID_IUnknown ) )
{
*ppvObject = iface;
}
else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
{
TRACE("Interface IDispatchEx not supported - returning NULL\n");
*ppvObject = NULL;
return E_NOINTERFACE;
}
else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
{
TRACE("Interface IObjectWithSite not supported - returning NULL\n");
*ppvObject = NULL;
return E_NOINTERFACE;
}
else
{
FIXME("Unsupported interface %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
IFileSystem3_AddRef(iface);
return S_OK;
}
static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
{
TRACE("%p\n", iface);
return 2;
}
static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
{
TRACE("%p\n", iface);
return 1;
}
static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
{
TRACE("(%p)->(%p)\n", iface, pctinfo);
*pctinfo = 1;
return S_OK;
}
static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
LCID lcid, ITypeInfo **ppTInfo)
{
TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
return get_typeinfo(IFileSystem3_tid, ppTInfo);
}
static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
{
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
ITypeInfo *typeinfo;
HRESULT hr;
TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
if(SUCCEEDED(hr))
{
hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgErr);
ITypeInfo_Release(typeinfo);
}
return hr;
}
static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
{
FIXME("%p %p\n", iface, ppdrives);
return E_NOTIMPL;
}
static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
BSTR Name, BSTR *Result)
{
BSTR ret;
TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
if (!Result) return E_POINTER;
if (Path && Name)
{
int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
/* if both parts have backslashes strip one from Path */
if (Path[path_len-1] == '\\' && Name[0] == '\\')
{
path_len -= 1;
ret = SysAllocStringLen(NULL, path_len + name_len);
if (ret)
{
strcpyW(ret, Path);
ret[path_len] = 0;
strcatW(ret, Name);
}
}
else if (Path[path_len-1] != '\\' && Name[0] != '\\')
{
static const WCHAR bsW[] = {'\\',0};
ret = SysAllocStringLen(NULL, path_len + name_len + 1);
if (ret)
{
strcpyW(ret, Path);
if (Path[path_len-1] != ':')
strcatW(ret, bsW);
strcatW(ret, Name);
}
}
else
{
ret = SysAllocStringLen(NULL, path_len + name_len);
if (ret)
{
strcpyW(ret, Path);
strcatW(ret, Name);
}
}
}
else if (Path || Name)
ret = SysAllocString(Path ? Path : Name);
else
ret = SysAllocStringLen(NULL, 0);
if (!ret) return E_OUTOFMEMORY;
*Result = ret;
return S_OK;
}
static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR Path,
BSTR *pbstrResult)
{
FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
return E_NOTIMPL;
}
static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
{
int i;
if(!path)
return 0;
for(i=len-1; i>=0; i--)
if(path[i]!='/' && path[i]!='\\')
break;
for(; i>=0; i--)
if(path[i]=='/' || path[i]=='\\')
break;
for(; i>=0; i--)
if(path[i]!='/' && path[i]!='\\')
break;
if(i < 0)
return 0;
if(path[i]==':' && i==1)
i++;
return i+1;
}
static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
BSTR *pbstrResult)
{
DWORD len;
TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
if(!pbstrResult)
return E_POINTER;
len = get_parent_folder_name(Path, SysStringLen(Path));
if(!len) {
*pbstrResult = NULL;
return S_OK;
}
*pbstrResult = SysAllocStringLen(Path, len);
if(!*pbstrResult)
return E_OUTOFMEMORY;
return S_OK;
}
static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
BSTR *pbstrResult)
{
int i, end;
TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
if(!pbstrResult)
return E_POINTER;
if(!Path) {
*pbstrResult = NULL;
return S_OK;
}
for(end=strlenW(Path)-1; end>=0; end--)
if(Path[end]!='/' && Path[end]!='\\')
break;
for(i=end; i>=0; i--)
if(Path[i]=='/' || Path[i]=='\\')
break;
i++;
if(i>end || (i==0 && end==1 && Path[1]==':')) {
*pbstrResult = NULL;
return S_OK;
}
*pbstrResult = SysAllocStringLen(Path+i, end-i+1);
if(!*pbstrResult)
return E_OUTOFMEMORY;
return S_OK;
}
static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
BSTR *pbstrResult)
{
int i, end;
TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
if(!pbstrResult)
return E_POINTER;
if(!Path) {
*pbstrResult = NULL;
return S_OK;
}
for(end=strlenW(Path)-1; end>=0; end--)
if(Path[end]!='/' && Path[end]!='\\')
break;
for(i=end; i>=0; i--) {
if(Path[i]=='.' && Path[end+1]!='.')
end = i-1;
if(Path[i]=='/' || Path[i]=='\\')
break;
}
i++;
if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
*pbstrResult = NULL;
return S_OK;
}
*pbstrResult = SysAllocStringLen(Path+i, end-i+1);
if(!*pbstrResult)
return E_OUTOFMEMORY;
return S_OK;
}
static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR Path,
BSTR *pbstrResult)
{
FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
return E_NOTIMPL;
}
static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
BSTR *pbstrResult)
{
static const WCHAR cur_path[] = {'.',0};
WCHAR buf[MAX_PATH], ch;
const WCHAR *path;
DWORD i, beg, len, exp_len;
WIN32_FIND_DATAW fdata;
HANDLE fh;
TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
if(!pbstrResult)
return E_POINTER;
if(!Path)
path = cur_path;
else
path = Path;
len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
if(!len)
return E_FAIL;
buf[0] = toupperW(buf[0]);
if(len>3 && buf[len-1] == '\\')
buf[--len] = 0;
for(beg=3, i=3; i<=len; i++) {
if(buf[i]!='\\' && buf[i])
continue;
ch = buf[i];
buf[i] = 0;
fh = FindFirstFileW(buf, &fdata);
if(fh == INVALID_HANDLE_VALUE)
break;
exp_len = strlenW(fdata.cFileName);
if(exp_len == i-beg)
memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
FindClose(fh);
buf[i] = ch;
beg = i+1;
}
*pbstrResult = SysAllocString(buf);
if(!*pbstrResult)
return E_OUTOFMEMORY;
return S_OK;
}
static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
{
static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
DWORD random;
TRACE("%p %p\n", iface, pbstrResult);
if(!pbstrResult)
return E_POINTER;
*pbstrResult = SysAllocStringLen(NULL, 12);
if(!*pbstrResult)
return E_OUTOFMEMORY;
if(!RtlGenRandom(&random, sizeof(random)))
return E_FAIL;
sprintfW(*pbstrResult, fmt, random & 0xfffff);
return S_OK;
}
static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
VARIANT_BOOL *pfExists)
{
FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
return E_NOTIMPL;
}
static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
{
DWORD attrs;
TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
if (!ret) return E_POINTER;
attrs = GetFileAttributesW(path);
*ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
{
DWORD attrs;
TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
if (!ret) return E_POINTER;
attrs = GetFileAttributesW(path);
*ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
IDrive **ppdrive)
{
FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
return E_NOTIMPL;
}
static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
IFile **ppfile)
{
TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
if(!ppfile)
return E_POINTER;
if(!FilePath)
return E_INVALIDARG;
return create_file(FilePath, ppfile);
}
static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
IFolder **folder)
{
DWORD attrs;
TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
if(!folder)
return E_POINTER;
*folder = NULL;
if(!FolderPath)
return E_INVALIDARG;
attrs = GetFileAttributesW(FolderPath);
if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
return CTL_E_PATHNOTFOUND;
return create_folder(FolderPath, folder);
}
static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
SpecialFolderConst SpecialFolder,
IFolder **ppfolder)
{
FIXME("%p %d %p\n", iface, SpecialFolder, ppfolder);
return E_NOTIMPL;
}
static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
{
WCHAR path[MAX_PATH];
DWORD len, name_len;
WIN32_FIND_DATAW ffd;
HANDLE f;
f = FindFirstFileW(file, &ffd);
if(f == INVALID_HANDLE_VALUE)
return create_error(GetLastError());
len = get_parent_folder_name(file, file_len);
if(len+1 >= MAX_PATH) {
FindClose(f);
return E_FAIL;
}
if(len) {
memcpy(path, file, len*sizeof(WCHAR));
path[len++] = '\\';
}
do {
if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
continue;
name_len = strlenW(ffd.cFileName);
if(len+name_len+1 >= MAX_PATH) {
FindClose(f);
return E_FAIL;
}
memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
TRACE("deleting %s\n", debugstr_w(path));
if(!DeleteFileW(path)) {
if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
|| !DeleteFileW(path)) {
FindClose(f);
return create_error(GetLastError());
}
}
} while(FindNextFileW(f, &ffd));
FindClose(f);
return S_OK;
}
static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
VARIANT_BOOL Force)
{
TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
if(!FileSpec)
return E_POINTER;
return delete_file(FileSpec, SysStringLen(FileSpec), Force);
}
static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
{
WCHAR path[MAX_PATH];
DWORD len, name_len;
WIN32_FIND_DATAW ffd;
HANDLE f;
HRESULT hr;
f = FindFirstFileW(folder, &ffd);
if(f == INVALID_HANDLE_VALUE)
return create_error(GetLastError());
len = get_parent_folder_name(folder, folder_len);
if(len+1 >= MAX_PATH) {
FindClose(f);
return E_FAIL;
}
if(len) {
memcpy(path, folder, len*sizeof(WCHAR));
path[len++] = '\\';
}
do {
if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
continue;
if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
(ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
continue;
name_len = strlenW(ffd.cFileName);
if(len+name_len+3 >= MAX_PATH) {
FindClose(f);
return E_FAIL;
}
memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
path[len+name_len] = '\\';
path[len+name_len+1] = '*';
path[len+name_len+2] = 0;
hr = delete_file(path, len+name_len+2, force);
if(FAILED(hr)) {
FindClose(f);
return hr;
}
hr = delete_folder(path, len+name_len+2, force);
if(FAILED(hr)) {
FindClose(f);
return hr;
}
path[len+name_len] = 0;
TRACE("deleting %s\n", debugstr_w(path));
if(!RemoveDirectoryW(path)) {
FindClose(f);
return create_error(GetLastError());
}
} while(FindNextFileW(f, &ffd));
FindClose(f);
return S_OK;
}
static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
VARIANT_BOOL Force)
{
TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
if(!FolderSpec)
return E_POINTER;
return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
}
static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
BSTR Destination)
{
FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
return E_NOTIMPL;
}
static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
BSTR Destination)
{
FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
return E_NOTIMPL;
}
static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
{
DWORD attrs;
WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
DWORD src_len, dst_len, name_len;
WIN32_FIND_DATAW ffd;
HANDLE f;
HRESULT hr;
if(!source[0] || !destination[0])
return E_INVALIDARG;
attrs = GetFileAttributesW(destination);
if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
attrs = GetFileAttributesW(source);
if(attrs == INVALID_FILE_ATTRIBUTES)
return create_error(GetLastError());
else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
return CTL_E_FILENOTFOUND;
if(!CopyFileW(source, destination, !overwrite))
return create_error(GetLastError());
return S_OK;
}
f = FindFirstFileW(source, &ffd);
if(f == INVALID_HANDLE_VALUE)
return CTL_E_FILENOTFOUND;
src_len = get_parent_folder_name(source, source_len);
if(src_len+1 >= MAX_PATH)
return E_FAIL;
if(src_len) {
memcpy(src_path, source, src_len*sizeof(WCHAR));
src_path[src_len++] = '\\';
}
dst_len = destination_len;
if(dst_len+1 >= MAX_PATH) {
FindClose(f);
return E_FAIL;
}
memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
dst_path[dst_len++] = '\\';
hr = CTL_E_FILENOTFOUND;
do {
if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
continue;
name_len = strlenW(ffd.cFileName);
if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
FindClose(f);
return E_FAIL;
}
memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
if(!CopyFileW(src_path, dst_path, !overwrite)) {
FindClose(f);
return create_error(GetLastError());
}else {
hr = S_OK;
}
} while(FindNextFileW(f, &ffd));
FindClose(f);
return hr;
}
static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
BSTR Destination, VARIANT_BOOL OverWriteFiles)
{
TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
if(!Source || !Destination)
return E_POINTER;
return copy_file(Source, SysStringLen(Source), Destination,
SysStringLen(Destination), OverWriteFiles);
}
static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
DWORD destination_len, VARIANT_BOOL overwrite)
{
DWORD tmp, src_len, dst_len, name_len;
WCHAR src[MAX_PATH], dst[MAX_PATH];
WIN32_FIND_DATAW ffd;
HANDLE f;
HRESULT hr;
BOOL copied = FALSE;
if(!source[0] || !destination[0])
return E_INVALIDARG;
dst_len = destination_len;
if(dst_len+1 >= MAX_PATH)
return E_FAIL;
memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
(tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
tmp&FILE_ATTRIBUTE_DIRECTORY) {
if(!CreateDirectoryW(dst, NULL)) {
if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
tmp = GetFileAttributesW(dst);
if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
return CTL_E_FILEALREADYEXISTS;
}else {
return create_error(GetLastError());
}
}
copied = TRUE;
src_len = source_len;
if(src_len+2 >= MAX_PATH)
return E_FAIL;
memcpy(src, source, src_len*sizeof(WCHAR));
src[src_len++] = '\\';
src[src_len] = '*';
src[src_len+1] = 0;
hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
return create_error(GetLastError());
f = FindFirstFileW(src, &ffd);
}else {
src_len = get_parent_folder_name(source, source_len);
if(src_len+2 >= MAX_PATH)
return E_FAIL;
memcpy(src, source, src_len*sizeof(WCHAR));
if(src_len)
src[src_len++] = '\\';
f = FindFirstFileW(source, &ffd);
}
if(f == INVALID_HANDLE_VALUE)
return CTL_E_PATHNOTFOUND;
dst[dst_len++] = '\\';
dst[dst_len] = 0;
do {
if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
continue;
if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
(ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
continue;
name_len = strlenW(ffd.cFileName);
if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
FindClose(f);
return E_FAIL;
}
memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
dst[dst_len+name_len] = 0;
memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
src[src_len+name_len] = '\\';
src[src_len+name_len+1] = '*';
src[src_len+name_len+2] = 0;
TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
if(!CreateDirectoryW(dst, NULL)) {
if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
tmp = GetFileAttributesW(dst);
if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
FindClose(f);
return CTL_E_FILEALREADYEXISTS;
}
}else {
FindClose(f);
return create_error(GetLastError());
}
return create_error(GetLastError());
}
copied = TRUE;
hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
FindClose(f);
return hr;
}
hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
FindClose(f);
return hr;
}
} while(FindNextFileW(f, &ffd));
FindClose(f);
return copied ? S_OK : CTL_E_PATHNOTFOUND;
}
static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
BSTR Destination, VARIANT_BOOL OverWriteFiles)
{
TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
if(!Source || !Destination)
return E_POINTER;
return copy_folder(Source, SysStringLen(Source), Destination,
SysStringLen(Destination), OverWriteFiles);
}
static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
IFolder **folder)
{
BOOL ret;
TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
ret = CreateDirectoryW(path, NULL);
if (!ret)
{
*folder = NULL;
if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
return HRESULT_FROM_WIN32(GetLastError());
}
return create_folder(path, folder);
}
static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR FileName,
VARIANT_BOOL Overwrite, VARIANT_BOOL Unicode,
ITextStream **ppts)
{
FIXME("%p %s %d %d %p\n", iface, debugstr_w(FileName), Overwrite, Unicode, ppts);
return E_NOTIMPL;
}
static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
IOMode mode, VARIANT_BOOL create,
Tristate format, ITextStream **stream)
{
FIXME("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
return create_textstream(mode, stream);
}
static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
StandardStreamTypes StandardStreamType,
VARIANT_BOOL Unicode,
ITextStream **ppts)
{
FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
return E_NOTIMPL;
}
static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
{
static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
DWORDLONG version;
WORD a, b, c, d;
version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
a = (WORD)( version >> 48);
b = (WORD)((version >> 32) & 0xffff);
c = (WORD)((version >> 16) & 0xffff);
d = (WORD)( version & 0xffff);
sprintfW(ver, fmtW, a, b, c, d);
}
static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
{
static const WCHAR rootW[] = {'\\',0};
VS_FIXEDFILEINFO *info;
WCHAR ver[30];
void *ptr;
DWORD len;
BOOL ret;
TRACE("%p %s %p\n", iface, debugstr_w(name), version);
len = GetFileVersionInfoSizeW(name, NULL);
if (!len)
return HRESULT_FROM_WIN32(GetLastError());
ptr = heap_alloc(len);
if (!GetFileVersionInfoW(name, 0, len, ptr))
{
heap_free(ptr);
return HRESULT_FROM_WIN32(GetLastError());
}
ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
heap_free(ptr);
if (!ret)
return HRESULT_FROM_WIN32(GetLastError());
get_versionstring(info, ver);
*version = SysAllocString(ver);
TRACE("version=%s\n", debugstr_w(ver));
return S_OK;
}
static const struct IFileSystem3Vtbl filesys_vtbl =
{
filesys_QueryInterface,
filesys_AddRef,
filesys_Release,
filesys_GetTypeInfoCount,
filesys_GetTypeInfo,
filesys_GetIDsOfNames,
filesys_Invoke,
filesys_get_Drives,
filesys_BuildPath,
filesys_GetDriveName,
filesys_GetParentFolderName,
filesys_GetFileName,
filesys_GetBaseName,
filesys_GetExtensionName,
filesys_GetAbsolutePathName,
filesys_GetTempName,
filesys_DriveExists,
filesys_FileExists,
filesys_FolderExists,
filesys_GetDrive,
filesys_GetFile,
filesys_GetFolder,
filesys_GetSpecialFolder,
filesys_DeleteFile,
filesys_DeleteFolder,
filesys_MoveFile,
filesys_MoveFolder,
filesys_CopyFile,
filesys_CopyFolder,
filesys_CreateFolder,
filesys_CreateTextFile,
filesys_OpenTextFile,
filesys_GetStandardStream,
filesys_GetFileVersion
};
static IFileSystem3 filesystem = { &filesys_vtbl };
HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
{
TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
return IFileSystem3_QueryInterface(&filesystem, riid, ppv);
}