| /* | |
| * 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); | |
| static const WCHAR bsW[] = {'\\',0}; | |
| static const WCHAR utf16bom = 0xfeff; | |
| struct filesystem { | |
| struct provideclassinfo classinfo; | |
| IFileSystem3 IFileSystem3_iface; | |
| }; | |
| struct foldercollection { | |
| struct provideclassinfo classinfo; | |
| IFolderCollection IFolderCollection_iface; | |
| LONG ref; | |
| BSTR path; | |
| }; | |
| struct filecollection { | |
| struct provideclassinfo classinfo; | |
| IFileCollection IFileCollection_iface; | |
| LONG ref; | |
| BSTR path; | |
| }; | |
| struct drivecollection { | |
| struct provideclassinfo classinfo; | |
| IDriveCollection IDriveCollection_iface; | |
| LONG ref; | |
| DWORD drives; | |
| LONG count; | |
| }; | |
| struct enumdata { | |
| union | |
| { | |
| struct | |
| { | |
| struct foldercollection *coll; | |
| HANDLE find; | |
| } foldercoll; | |
| struct | |
| { | |
| struct filecollection *coll; | |
| HANDLE find; | |
| } filecoll; | |
| struct | |
| { | |
| struct drivecollection *coll; | |
| INT cur; | |
| } drivecoll; | |
| } u; | |
| }; | |
| struct enumvariant { | |
| IEnumVARIANT IEnumVARIANT_iface; | |
| LONG ref; | |
| struct enumdata data; | |
| }; | |
| struct drive { | |
| struct provideclassinfo classinfo; | |
| IDrive IDrive_iface; | |
| LONG ref; | |
| BSTR root; | |
| }; | |
| struct folder { | |
| struct provideclassinfo classinfo; | |
| IFolder IFolder_iface; | |
| LONG ref; | |
| BSTR path; | |
| }; | |
| struct file { | |
| struct provideclassinfo classinfo; | |
| IFile IFile_iface; | |
| LONG ref; | |
| WCHAR *path; | |
| }; | |
| struct textstream { | |
| struct provideclassinfo classinfo; | |
| ITextStream ITextStream_iface; | |
| LONG ref; | |
| IOMode mode; | |
| BOOL unicode; | |
| BOOL first_read; | |
| LARGE_INTEGER size; | |
| HANDLE file; | |
| }; | |
| enum iotype { | |
| IORead, | |
| IOWrite | |
| }; | |
| static inline struct filesystem *impl_from_IFileSystem3(IFileSystem3 *iface) | |
| { | |
| return CONTAINING_RECORD(iface, struct filesystem, IFileSystem3_iface); | |
| } | |
| static inline struct drive *impl_from_IDrive(IDrive *iface) | |
| { | |
| return CONTAINING_RECORD(iface, struct drive, IDrive_iface); | |
| } | |
| 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 filecollection *impl_from_IFileCollection(IFileCollection *iface) | |
| { | |
| return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface); | |
| } | |
| static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface) | |
| { | |
| return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_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 HRESULT create_folder(const WCHAR*, IFolder**); | |
| static HRESULT create_file(BSTR, IFile**); | |
| static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**); | |
| static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**); | |
| static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data) | |
| { | |
| static const WCHAR dotdotW[] = {'.','.',0}; | |
| static const WCHAR dotW[] = {'.',0}; | |
| return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && | |
| strcmpW(data->cFileName, dotdotW) && | |
| strcmpW(data->cFileName, dotW); | |
| } | |
| static inline BOOL is_file_data(const WIN32_FIND_DATAW *data) | |
| { | |
| return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); | |
| } | |
| static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data) | |
| { | |
| int len = SysStringLen(path); | |
| WCHAR buffW[MAX_PATH]; | |
| strcpyW(buffW, path); | |
| if (path[len-1] != '\\') | |
| strcatW(buffW, bsW); | |
| strcatW(buffW, data->cFileName); | |
| return SysAllocString(buffW); | |
| } | |
| static BOOL textstream_check_iomode(struct textstream *This, enum iotype type) | |
| { | |
| if (type == IORead) | |
| return This->mode == ForWriting || This->mode == ForAppending; | |
| else | |
| return This->mode == ForReading; | |
| } | |
| 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 = &This->ITextStream_iface; | |
| } | |
| else if (IsEqualIID(riid, &IID_IProvideClassInfo)) | |
| { | |
| *obj = &This->classinfo.IProvideClassInfo_iface; | |
| } | |
| else | |
| return E_NOINTERFACE; | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| return S_OK; | |
| } | |
| 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) | |
| { | |
| CloseHandle(This->file); | |
| 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); | |
| LARGE_INTEGER pos, dist; | |
| TRACE("(%p)->(%p)\n", This, eos); | |
| if (!eos) | |
| return E_POINTER; | |
| if (textstream_check_iomode(This, IORead)) { | |
| *eos = VARIANT_TRUE; | |
| return CTL_E_BADFILEMODE; | |
| } | |
| dist.QuadPart = 0; | |
| if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT)) | |
| return E_FAIL; | |
| *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE; | |
| return S_OK; | |
| } | |
| 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; | |
| } | |
| /* | |
| Reads 'toread' bytes from a file, converts if needed | |
| BOM is skipped if 'bof' is set. | |
| */ | |
| static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text) | |
| { | |
| HRESULT hr = S_OK; | |
| DWORD read; | |
| char *buff; | |
| BOOL ret; | |
| if (toread == 0) { | |
| *text = SysAllocStringLen(NULL, 0); | |
| return *text ? S_FALSE : E_OUTOFMEMORY; | |
| } | |
| if (toread < sizeof(WCHAR)) | |
| return CTL_E_ENDOFFILE; | |
| buff = heap_alloc(toread); | |
| if (!buff) | |
| return E_OUTOFMEMORY; | |
| ret = ReadFile(stream->file, buff, toread, &read, NULL); | |
| if (!ret || toread != read) { | |
| WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError()); | |
| heap_free(buff); | |
| return E_FAIL; | |
| } | |
| if (stream->unicode) { | |
| int i = 0; | |
| /* skip BOM */ | |
| if (bof && *(WCHAR*)buff == utf16bom) { | |
| read -= sizeof(WCHAR); | |
| i += sizeof(WCHAR); | |
| } | |
| *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR)); | |
| if (!*text) hr = E_OUTOFMEMORY; | |
| } | |
| else { | |
| INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0); | |
| *text = SysAllocStringLen(NULL, len); | |
| if (*text) | |
| MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len); | |
| else | |
| hr = E_OUTOFMEMORY; | |
| } | |
| heap_free(buff); | |
| return hr; | |
| } | |
| static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text) | |
| { | |
| struct textstream *This = impl_from_ITextStream(iface); | |
| LARGE_INTEGER start, end, dist; | |
| DWORD toread; | |
| HRESULT hr; | |
| TRACE("(%p)->(%d %p)\n", This, len, text); | |
| if (!text) | |
| return E_POINTER; | |
| *text = NULL; | |
| if (len <= 0) | |
| return len == 0 ? S_OK : E_INVALIDARG; | |
| if (textstream_check_iomode(This, IORead)) | |
| return CTL_E_BADFILEMODE; | |
| if (!This->first_read) { | |
| VARIANT_BOOL eos; | |
| /* check for EOF */ | |
| hr = ITextStream_get_AtEndOfStream(iface, &eos); | |
| if (FAILED(hr)) | |
| return hr; | |
| if (eos == VARIANT_TRUE) | |
| return CTL_E_ENDOFFILE; | |
| } | |
| /* read everything from current position */ | |
| dist.QuadPart = 0; | |
| SetFilePointerEx(This->file, dist, &start, FILE_CURRENT); | |
| SetFilePointerEx(This->file, dist, &end, FILE_END); | |
| toread = end.QuadPart - start.QuadPart; | |
| /* rewind back */ | |
| dist.QuadPart = start.QuadPart; | |
| SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN); | |
| This->first_read = FALSE; | |
| if (This->unicode) len *= sizeof(WCHAR); | |
| hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text); | |
| if (FAILED(hr)) | |
| return hr; | |
| else | |
| return toread <= len ? S_FALSE : S_OK; | |
| } | |
| static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text) | |
| { | |
| struct textstream *This = impl_from_ITextStream(iface); | |
| VARIANT_BOOL eos; | |
| HRESULT hr; | |
| FIXME("(%p)->(%p): stub\n", This, text); | |
| if (!text) | |
| return E_POINTER; | |
| *text = NULL; | |
| if (textstream_check_iomode(This, IORead)) | |
| return CTL_E_BADFILEMODE; | |
| /* check for EOF */ | |
| hr = ITextStream_get_AtEndOfStream(iface, &eos); | |
| if (FAILED(hr)) | |
| return hr; | |
| if (eos == VARIANT_TRUE) | |
| return CTL_E_ENDOFFILE; | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text) | |
| { | |
| struct textstream *This = impl_from_ITextStream(iface); | |
| LARGE_INTEGER start, end, dist; | |
| DWORD toread; | |
| HRESULT hr; | |
| TRACE("(%p)->(%p)\n", This, text); | |
| if (!text) | |
| return E_POINTER; | |
| *text = NULL; | |
| if (textstream_check_iomode(This, IORead)) | |
| return CTL_E_BADFILEMODE; | |
| if (!This->first_read) { | |
| VARIANT_BOOL eos; | |
| /* check for EOF */ | |
| hr = ITextStream_get_AtEndOfStream(iface, &eos); | |
| if (FAILED(hr)) | |
| return hr; | |
| if (eos == VARIANT_TRUE) | |
| return CTL_E_ENDOFFILE; | |
| } | |
| /* read everything from current position */ | |
| dist.QuadPart = 0; | |
| SetFilePointerEx(This->file, dist, &start, FILE_CURRENT); | |
| SetFilePointerEx(This->file, dist, &end, FILE_END); | |
| toread = end.QuadPart - start.QuadPart; | |
| /* rewind back */ | |
| dist.QuadPart = start.QuadPart; | |
| SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN); | |
| This->first_read = FALSE; | |
| hr = textstream_read(This, toread, start.QuadPart == 0, text); | |
| return FAILED(hr) ? hr : S_FALSE; | |
| } | |
| static HRESULT textstream_writestr(struct textstream *stream, BSTR text) | |
| { | |
| DWORD written = 0; | |
| BOOL ret; | |
| if (stream->unicode) { | |
| ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL); | |
| return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError()); | |
| } else { | |
| DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL); | |
| char *buffA; | |
| HRESULT hr; | |
| buffA = heap_alloc(len); | |
| if (!buffA) | |
| return E_OUTOFMEMORY; | |
| WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL); | |
| ret = WriteFile(stream->file, buffA, len, &written, NULL); | |
| hr = (ret && written == len) ? S_OK : create_error(GetLastError()); | |
| heap_free(buffA); | |
| return hr; | |
| } | |
| } | |
| static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text) | |
| { | |
| struct textstream *This = impl_from_ITextStream(iface); | |
| TRACE("(%p)->(%s)\n", This, debugstr_w(text)); | |
| if (textstream_check_iomode(This, IOWrite)) | |
| return CTL_E_BADFILEMODE; | |
| return textstream_writestr(This, text); | |
| } | |
| static HRESULT textstream_writecrlf(struct textstream *stream) | |
| { | |
| static const WCHAR crlfW[] = {'\r','\n'}; | |
| static const char crlfA[] = {'\r','\n'}; | |
| DWORD written = 0, len; | |
| const void *ptr; | |
| BOOL ret; | |
| if (stream->unicode) { | |
| ptr = crlfW; | |
| len = sizeof(crlfW); | |
| } | |
| else { | |
| ptr = crlfA; | |
| len = sizeof(crlfA); | |
| } | |
| ret = WriteFile(stream->file, ptr, len, &written, NULL); | |
| return (ret && written == len) ? S_OK : create_error(GetLastError()); | |
| } | |
| static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text) | |
| { | |
| struct textstream *This = impl_from_ITextStream(iface); | |
| HRESULT hr; | |
| TRACE("(%p)->(%s)\n", This, debugstr_w(text)); | |
| if (textstream_check_iomode(This, IOWrite)) | |
| return CTL_E_BADFILEMODE; | |
| hr = textstream_writestr(This, text); | |
| if (SUCCEEDED(hr)) | |
| hr = textstream_writecrlf(This); | |
| return hr; | |
| } | |
| 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); | |
| HRESULT hr = S_OK; | |
| TRACE("(%p)\n", This); | |
| if(!CloseHandle(This->file)) | |
| hr = S_FALSE; | |
| This->file = NULL; | |
| return hr; | |
| } | |
| 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(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret) | |
| { | |
| struct textstream *stream; | |
| DWORD access = 0; | |
| /* map access mode */ | |
| switch (mode) | |
| { | |
| case ForReading: | |
| access = GENERIC_READ; | |
| break; | |
| case ForWriting: | |
| access = GENERIC_WRITE; | |
| break; | |
| case ForAppending: | |
| access = FILE_APPEND_DATA; | |
| break; | |
| default: | |
| return E_INVALIDARG; | |
| } | |
| stream = heap_alloc(sizeof(struct textstream)); | |
| if (!stream) return E_OUTOFMEMORY; | |
| stream->ITextStream_iface.lpVtbl = &textstreamvtbl; | |
| stream->ref = 1; | |
| stream->mode = mode; | |
| stream->unicode = unicode; | |
| stream->first_read = TRUE; | |
| stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL); | |
| if (stream->file == INVALID_HANDLE_VALUE) | |
| { | |
| HRESULT hr = create_error(GetLastError()); | |
| heap_free(stream); | |
| return hr; | |
| } | |
| if (mode == ForReading) | |
| GetFileSizeEx(stream->file, &stream->size); | |
| else | |
| stream->size.QuadPart = 0; | |
| /* Write Unicode BOM */ | |
| if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) { | |
| DWORD written = 0; | |
| BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL); | |
| if (!ret || written != sizeof(utf16bom)) { | |
| ITextStream_Release(&stream->ITextStream_iface); | |
| return create_error(GetLastError()); | |
| } | |
| } | |
| init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo); | |
| *ret = &stream->ITextStream_iface; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); | |
| *obj = NULL; | |
| if (IsEqualIID( riid, &IID_IDrive ) || | |
| IsEqualIID( riid, &IID_IDispatch ) || | |
| IsEqualIID( riid, &IID_IUnknown)) | |
| { | |
| *obj = &This->IDrive_iface; | |
| } | |
| else if (IsEqualIID( riid, &IID_IProvideClassInfo )) | |
| { | |
| *obj = &This->classinfo.IProvideClassInfo_iface; | |
| } | |
| else | |
| return E_NOINTERFACE; | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI drive_AddRef(IDrive *iface) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(%d)\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI drive_Release(IDrive *iface) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(%d)\n", This, ref); | |
| if (!ref) | |
| { | |
| SysFreeString(This->root); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| TRACE("(%p)->(%p)\n", This, pctinfo); | |
| *pctinfo = 1; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo, | |
| LCID lcid, ITypeInfo **ppTInfo) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); | |
| return get_typeinfo(IDrive_tid, ppTInfo); | |
| } | |
| static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid, | |
| LPOLESTR *rgszNames, UINT cNames, | |
| LCID lcid, DISPID *rgDispId) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| ITypeInfo *typeinfo; | |
| HRESULT hr; | |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); | |
| hr = get_typeinfo(IDrive_tid, &typeinfo); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); | |
| ITypeInfo_Release(typeinfo); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember, | |
| REFIID riid, LCID lcid, WORD wFlags, | |
| DISPPARAMS *pDispParams, VARIANT *pVarResult, | |
| EXCEPINFO *pExcepInfo, UINT *puArgErr) | |
| { | |
| struct drive *This = impl_from_IDrive(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(IDrive_tid, &typeinfo); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, | |
| pDispParams, pVarResult, pExcepInfo, puArgErr); | |
| ITypeInfo_Release(typeinfo); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| FIXME("(%p)->(%p): stub\n", This, path); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| TRACE("(%p)->(%p)\n", This, letter); | |
| if (!letter) | |
| return E_POINTER; | |
| *letter = SysAllocStringLen(This->root, 1); | |
| if (!*letter) | |
| return E_OUTOFMEMORY; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| FIXME("(%p)->(%p): stub\n", This, share_name); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| TRACE("(%p)->(%p)\n", This, type); | |
| switch (GetDriveTypeW(This->root)) | |
| { | |
| case DRIVE_REMOVABLE: | |
| *type = Removable; | |
| break; | |
| case DRIVE_FIXED: | |
| *type = Fixed; | |
| break; | |
| case DRIVE_REMOTE: | |
| *type = Remote; | |
| break; | |
| case DRIVE_CDROM: | |
| *type = CDRom; | |
| break; | |
| case DRIVE_RAMDISK: | |
| *type = RamDisk; | |
| break; | |
| default: | |
| *type = UnknownType; | |
| break; | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| FIXME("(%p)->(%p): stub\n", This, folder); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v) | |
| { | |
| HRESULT hr = S_OK; | |
| if (src->u.HighPart || src->u.LowPart > INT_MAX) | |
| { | |
| V_VT(v) = VT_R8; | |
| hr = VarR8FromUI8(src->QuadPart, &V_R8(v)); | |
| } | |
| else | |
| { | |
| V_VT(v) = VT_I4; | |
| V_I4(v) = src->u.LowPart; | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| ULARGE_INTEGER avail; | |
| TRACE("(%p)->(%p)\n", This, v); | |
| if (!v) | |
| return E_POINTER; | |
| if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL)) | |
| return E_FAIL; | |
| return variant_from_largeint(&avail, v); | |
| } | |
| static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| ULARGE_INTEGER freespace; | |
| TRACE("(%p)->(%p)\n", This, v); | |
| if (!v) | |
| return E_POINTER; | |
| if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL)) | |
| return E_FAIL; | |
| return variant_from_largeint(&freespace, v); | |
| } | |
| static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| ULARGE_INTEGER total; | |
| TRACE("(%p)->(%p)\n", This, v); | |
| if (!v) | |
| return E_POINTER; | |
| if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL)) | |
| return E_FAIL; | |
| return variant_from_largeint(&total, v); | |
| } | |
| static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| WCHAR nameW[MAX_PATH+1]; | |
| BOOL ret; | |
| TRACE("(%p)->(%p)\n", This, name); | |
| if (!name) | |
| return E_POINTER; | |
| *name = NULL; | |
| ret = GetVolumeInformationW(This->root, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, NULL, NULL, NULL, 0); | |
| if (ret) | |
| *name = SysAllocString(nameW); | |
| return ret ? S_OK : E_FAIL; | |
| } | |
| static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| FIXME("(%p)->(%s): stub\n", This, debugstr_w(name)); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| WCHAR nameW[MAX_PATH+1]; | |
| BOOL ret; | |
| TRACE("(%p)->(%p)\n", This, fs); | |
| if (!fs) | |
| return E_POINTER; | |
| *fs = NULL; | |
| ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, sizeof(nameW)/sizeof(WCHAR)); | |
| if (ret) | |
| *fs = SysAllocString(nameW); | |
| return ret ? S_OK : E_FAIL; | |
| } | |
| static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| BOOL ret; | |
| TRACE("(%p)->(%p)\n", This, serial); | |
| if (!serial) | |
| return E_POINTER; | |
| ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0); | |
| return ret ? S_OK : E_FAIL; | |
| } | |
| static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready) | |
| { | |
| struct drive *This = impl_from_IDrive(iface); | |
| ULARGE_INTEGER freespace; | |
| BOOL ret; | |
| TRACE("(%p)->(%p)\n", This, ready); | |
| if (!ready) | |
| return E_POINTER; | |
| ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL); | |
| *ready = ret ? VARIANT_TRUE : VARIANT_FALSE; | |
| return S_OK; | |
| } | |
| static const IDriveVtbl drivevtbl = { | |
| drive_QueryInterface, | |
| drive_AddRef, | |
| drive_Release, | |
| drive_GetTypeInfoCount, | |
| drive_GetTypeInfo, | |
| drive_GetIDsOfNames, | |
| drive_Invoke, | |
| drive_get_Path, | |
| drive_get_DriveLetter, | |
| drive_get_ShareName, | |
| drive_get_DriveType, | |
| drive_get_RootFolder, | |
| drive_get_AvailableSpace, | |
| drive_get_FreeSpace, | |
| drive_get_TotalSize, | |
| drive_get_VolumeName, | |
| drive_put_VolumeName, | |
| drive_get_FileSystem, | |
| drive_get_SerialNumber, | |
| drive_get_IsReady | |
| }; | |
| static HRESULT create_drive(WCHAR letter, IDrive **drive) | |
| { | |
| struct drive *This; | |
| *drive = NULL; | |
| This = heap_alloc(sizeof(*This)); | |
| if (!This) return E_OUTOFMEMORY; | |
| This->IDrive_iface.lpVtbl = &drivevtbl; | |
| This->ref = 1; | |
| This->root = SysAllocStringLen(NULL, 3); | |
| if (!This->root) | |
| { | |
| heap_free(This); | |
| return E_OUTOFMEMORY; | |
| } | |
| This->root[0] = letter; | |
| This->root[1] = ':'; | |
| This->root[2] = '\\'; | |
| This->root[3] = 0; | |
| init_classinfo(&CLSID_Drive, (IUnknown *)&This->IDrive_iface, &This->classinfo); | |
| *drive = &This->IDrive_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->IFolderCollection_iface); | |
| FindClose(This->data.u.foldercoll.find); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file) | |
| { | |
| static const WCHAR allW[] = {'*',0}; | |
| WCHAR pathW[MAX_PATH]; | |
| int len; | |
| HANDLE handle; | |
| strcpyW(pathW, path); | |
| len = strlenW(pathW); | |
| if (len && pathW[len-1] != '\\') | |
| strcatW(pathW, bsW); | |
| strcatW(pathW, allW); | |
| handle = FindFirstFileW(pathW, data); | |
| if (handle == INVALID_HANDLE_VALUE) return 0; | |
| /* find first dir/file */ | |
| while (1) | |
| { | |
| if (file ? is_file_data(data) : is_dir_data(data)) | |
| break; | |
| if (!FindNextFileW(handle, data)) | |
| { | |
| FindClose(handle); | |
| return 0; | |
| } | |
| } | |
| return handle; | |
| } | |
| static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| HANDLE handle = This->data.u.foldercoll.find; | |
| WIN32_FIND_DATAW data; | |
| ULONG count = 0; | |
| TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched); | |
| if (fetched) | |
| *fetched = 0; | |
| if (!celt) return S_OK; | |
| if (!handle) | |
| { | |
| handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE); | |
| if (!handle) return S_FALSE; | |
| This->data.u.foldercoll.find = handle; | |
| } | |
| else | |
| { | |
| if (!FindNextFileW(handle, &data)) | |
| return S_FALSE; | |
| } | |
| do | |
| { | |
| if (is_dir_data(&data)) | |
| { | |
| IFolder *folder; | |
| HRESULT hr; | |
| BSTR str; | |
| str = get_full_path(This->data.u.foldercoll.coll->path, &data); | |
| hr = create_folder(str, &folder); | |
| SysFreeString(str); | |
| if (FAILED(hr)) return hr; | |
| V_VT(&var[count]) = VT_DISPATCH; | |
| V_DISPATCH(&var[count]) = (IDispatch*)folder; | |
| count++; | |
| if (count >= celt) break; | |
| } | |
| } while (FindNextFileW(handle, &data)); | |
| if (fetched) | |
| *fetched = count; | |
| return (count < celt) ? S_FALSE : S_OK; | |
| } | |
| static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| HANDLE handle = This->data.u.foldercoll.find; | |
| WIN32_FIND_DATAW data; | |
| TRACE("(%p)->(%d)\n", This, celt); | |
| if (!celt) return S_OK; | |
| if (!handle) | |
| { | |
| handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE); | |
| if (!handle) return S_FALSE; | |
| This->data.u.foldercoll.find = handle; | |
| } | |
| else | |
| { | |
| if (!FindNextFileW(handle, &data)) | |
| return S_FALSE; | |
| } | |
| do | |
| { | |
| if (is_dir_data(&data)) | |
| --celt; | |
| if (!celt) break; | |
| } while (FindNextFileW(handle, &data)); | |
| return celt ? S_FALSE : S_OK; | |
| } | |
| 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); | |
| TRACE("(%p)->(%p)\n", This, pclone); | |
| return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone); | |
| } | |
| 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.coll = collection; | |
| IFolderCollection_AddRef(&collection->IFolderCollection_iface); | |
| *newenum = (IUnknown*)&This->IEnumVARIANT_iface; | |
| return S_OK; | |
| } | |
| static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(%d)\n", This, ref); | |
| if (!ref) | |
| { | |
| IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface); | |
| FindClose(This->data.u.filecoll.find); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| HANDLE handle = This->data.u.filecoll.find; | |
| WIN32_FIND_DATAW data; | |
| ULONG count = 0; | |
| TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched); | |
| if (fetched) | |
| *fetched = 0; | |
| if (!celt) return S_OK; | |
| if (!handle) | |
| { | |
| handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE); | |
| if (!handle) return S_FALSE; | |
| This->data.u.filecoll.find = handle; | |
| } | |
| else if (!FindNextFileW(handle, &data)) | |
| return S_FALSE; | |
| do | |
| { | |
| if (is_file_data(&data)) | |
| { | |
| IFile *file; | |
| HRESULT hr; | |
| BSTR str; | |
| str = get_full_path(This->data.u.filecoll.coll->path, &data); | |
| hr = create_file(str, &file); | |
| SysFreeString(str); | |
| if (FAILED(hr)) return hr; | |
| V_VT(&var[count]) = VT_DISPATCH; | |
| V_DISPATCH(&var[count]) = (IDispatch*)file; | |
| if (++count >= celt) break; | |
| } | |
| } while (FindNextFileW(handle, &data)); | |
| if (fetched) | |
| *fetched = count; | |
| return (count < celt) ? S_FALSE : S_OK; | |
| } | |
| static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| HANDLE handle = This->data.u.filecoll.find; | |
| WIN32_FIND_DATAW data; | |
| TRACE("(%p)->(%d)\n", This, celt); | |
| if (!celt) return S_OK; | |
| if (!handle) | |
| { | |
| handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE); | |
| if (!handle) return S_FALSE; | |
| This->data.u.filecoll.find = handle; | |
| } | |
| else if (!FindNextFileW(handle, &data)) | |
| return S_FALSE; | |
| do | |
| { | |
| if (is_file_data(&data)) | |
| --celt; | |
| } while (celt && FindNextFileW(handle, &data)); | |
| return celt ? S_FALSE : S_OK; | |
| } | |
| static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| TRACE("(%p)\n", This); | |
| FindClose(This->data.u.filecoll.find); | |
| This->data.u.filecoll.find = NULL; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| TRACE("(%p)->(%p)\n", This, pclone); | |
| return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone); | |
| } | |
| static const IEnumVARIANTVtbl filecollenumvariantvtbl = { | |
| enumvariant_QueryInterface, | |
| enumvariant_AddRef, | |
| filecoll_enumvariant_Release, | |
| filecoll_enumvariant_Next, | |
| filecoll_enumvariant_Skip, | |
| filecoll_enumvariant_Reset, | |
| filecoll_enumvariant_Clone | |
| }; | |
| static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum) | |
| { | |
| struct enumvariant *This; | |
| *newenum = NULL; | |
| This = heap_alloc(sizeof(*This)); | |
| if (!This) return E_OUTOFMEMORY; | |
| This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl; | |
| This->ref = 1; | |
| This->data.u.filecoll.find = NULL; | |
| This->data.u.filecoll.coll = collection; | |
| IFileCollection_AddRef(&collection->IFileCollection_iface); | |
| *newenum = (IUnknown*)&This->IEnumVARIANT_iface; | |
| return S_OK; | |
| } | |
| static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(%d)\n", This, ref); | |
| if (!ref) | |
| { | |
| IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT find_next_drive(struct enumvariant *penum) | |
| { | |
| int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1; | |
| for (; i < 32; i++) | |
| if (penum->data.u.drivecoll.coll->drives & (1 << i)) | |
| { | |
| penum->data.u.drivecoll.cur = i; | |
| return S_OK; | |
| } | |
| return S_FALSE; | |
| } | |
| static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| ULONG count = 0; | |
| TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched); | |
| if (fetched) | |
| *fetched = 0; | |
| if (!celt) return S_OK; | |
| while (find_next_drive(This) == S_OK) | |
| { | |
| IDrive *drive; | |
| HRESULT hr; | |
| hr = create_drive('A' + This->data.u.drivecoll.cur, &drive); | |
| if (FAILED(hr)) return hr; | |
| V_VT(&var[count]) = VT_DISPATCH; | |
| V_DISPATCH(&var[count]) = (IDispatch*)drive; | |
| if (++count >= celt) break; | |
| } | |
| if (fetched) | |
| *fetched = count; | |
| return (count < celt) ? S_FALSE : S_OK; | |
| } | |
| static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| TRACE("(%p)->(%d)\n", This, celt); | |
| if (!celt) return S_OK; | |
| while (celt && find_next_drive(This) == S_OK) | |
| celt--; | |
| return celt ? S_FALSE : S_OK; | |
| } | |
| static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface) | |
| { | |
| struct enumvariant *This = impl_from_IEnumVARIANT(iface); | |
| TRACE("(%p)\n", This); | |
| This->data.u.drivecoll.cur = -1; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI drivecoll_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 drivecollenumvariantvtbl = { | |
| enumvariant_QueryInterface, | |
| enumvariant_AddRef, | |
| drivecoll_enumvariant_Release, | |
| drivecoll_enumvariant_Next, | |
| drivecoll_enumvariant_Skip, | |
| drivecoll_enumvariant_Reset, | |
| drivecoll_enumvariant_Clone | |
| }; | |
| static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum) | |
| { | |
| struct enumvariant *This; | |
| *newenum = NULL; | |
| This = heap_alloc(sizeof(*This)); | |
| if (!This) return E_OUTOFMEMORY; | |
| This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl; | |
| This->ref = 1; | |
| This->data.u.drivecoll.coll = collection; | |
| This->data.u.drivecoll.cur = -1; | |
| IDriveCollection_AddRef(&collection->IDriveCollection_iface); | |
| *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 = &This->IFolderCollection_iface; | |
| } | |
| else if (IsEqualIID( riid, &IID_IProvideClassInfo )) | |
| { | |
| *obj = &This->classinfo.IProvideClassInfo_iface; | |
| } | |
| else | |
| return E_NOINTERFACE; | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| 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 (is_dir_data(&data)) | |
| *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; | |
| } | |
| init_classinfo(&CLSID_Folders, (IUnknown *)&This->IFolderCollection_iface, &This->classinfo); | |
| *folders = &This->IFolderCollection_iface; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(iface); | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); | |
| *obj = NULL; | |
| if (IsEqualIID( riid, &IID_IFileCollection ) || | |
| IsEqualIID( riid, &IID_IDispatch ) || | |
| IsEqualIID( riid, &IID_IUnknown )) | |
| { | |
| *obj = &This->IFileCollection_iface; | |
| } | |
| else if (IsEqualIID( riid, &IID_IProvideClassInfo )) | |
| { | |
| *obj = &This->classinfo.IProvideClassInfo_iface; | |
| } | |
| else | |
| return E_NOINTERFACE; | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI filecoll_AddRef(IFileCollection *iface) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(iface); | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(%d)\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI filecoll_Release(IFileCollection *iface) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(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 filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(iface); | |
| TRACE("(%p)->(%p)\n", This, pctinfo); | |
| *pctinfo = 1; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo, | |
| LCID lcid, ITypeInfo **ppTInfo) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(iface); | |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); | |
| return get_typeinfo(IFileCollection_tid, ppTInfo); | |
| } | |
| static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid, | |
| LPOLESTR *rgszNames, UINT cNames, | |
| LCID lcid, DISPID *rgDispId) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(iface); | |
| ITypeInfo *typeinfo; | |
| HRESULT hr; | |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); | |
| hr = get_typeinfo(IFileCollection_tid, &typeinfo); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); | |
| ITypeInfo_Release(typeinfo); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember, | |
| REFIID riid, LCID lcid, WORD wFlags, | |
| DISPPARAMS *pDispParams, VARIANT *pVarResult, | |
| EXCEPINFO *pExcepInfo, UINT *puArgErr) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(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(IFileCollection_tid, &typeinfo); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, | |
| pDispParams, pVarResult, pExcepInfo, puArgErr); | |
| ITypeInfo_Release(typeinfo); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(iface); | |
| FIXME("(%p)->(%p)\n", This, file); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(iface); | |
| TRACE("(%p)->(%p)\n", This, ppenum); | |
| if(!ppenum) | |
| return E_POINTER; | |
| return create_filecoll_enum(This, ppenum); | |
| } | |
| static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count) | |
| { | |
| struct filecollection *This = impl_from_IFileCollection(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 (is_file_data(&data)) | |
| *count += 1; | |
| } while (FindNextFileW(handle, &data)); | |
| FindClose(handle); | |
| return S_OK; | |
| } | |
| static const IFileCollectionVtbl filecollectionvtbl = { | |
| filecoll_QueryInterface, | |
| filecoll_AddRef, | |
| filecoll_Release, | |
| filecoll_GetTypeInfoCount, | |
| filecoll_GetTypeInfo, | |
| filecoll_GetIDsOfNames, | |
| filecoll_Invoke, | |
| filecoll_get_Item, | |
| filecoll_get__NewEnum, | |
| filecoll_get_Count | |
| }; | |
| static HRESULT create_filecoll(BSTR path, IFileCollection **files) | |
| { | |
| struct filecollection *This; | |
| *files = NULL; | |
| This = heap_alloc(sizeof(*This)); | |
| if (!This) return E_OUTOFMEMORY; | |
| This->IFileCollection_iface.lpVtbl = &filecollectionvtbl; | |
| This->ref = 1; | |
| This->path = SysAllocString(path); | |
| if (!This->path) | |
| { | |
| heap_free(This); | |
| return E_OUTOFMEMORY; | |
| } | |
| init_classinfo(&CLSID_Files, (IUnknown *)&This->IFileCollection_iface, &This->classinfo); | |
| *files = &This->IFileCollection_iface; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); | |
| *obj = NULL; | |
| if (IsEqualIID( riid, &IID_IDriveCollection ) || | |
| IsEqualIID( riid, &IID_IDispatch ) || | |
| IsEqualIID( riid, &IID_IUnknown )) | |
| { | |
| *obj = &This->IDriveCollection_iface; | |
| } | |
| else if (IsEqualIID( riid, &IID_IProvideClassInfo )) | |
| { | |
| *obj = &This->classinfo.IProvideClassInfo_iface; | |
| } | |
| else | |
| return E_NOINTERFACE; | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(%d)\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI drivecoll_Release(IDriveCollection *iface) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(%d)\n", This, ref); | |
| if (!ref) | |
| heap_free(This); | |
| return ref; | |
| } | |
| static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| TRACE("(%p)->(%p)\n", This, pctinfo); | |
| *pctinfo = 1; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo, | |
| LCID lcid, ITypeInfo **ppTInfo) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); | |
| return get_typeinfo(IDriveCollection_tid, ppTInfo); | |
| } | |
| static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid, | |
| LPOLESTR *rgszNames, UINT cNames, | |
| LCID lcid, DISPID *rgDispId) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| ITypeInfo *typeinfo; | |
| HRESULT hr; | |
| TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); | |
| hr = get_typeinfo(IDriveCollection_tid, &typeinfo); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId); | |
| ITypeInfo_Release(typeinfo); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember, | |
| REFIID riid, LCID lcid, WORD wFlags, | |
| DISPPARAMS *pDispParams, VARIANT *pVarResult, | |
| EXCEPINFO *pExcepInfo, UINT *puArgErr) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(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(IDriveCollection_tid, &typeinfo); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags, | |
| pDispParams, pVarResult, pExcepInfo, puArgErr); | |
| ITypeInfo_Release(typeinfo); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| FIXME("(%p)->(%p): stub\n", This, drive); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| TRACE("(%p)->(%p)\n", This, ppenum); | |
| if(!ppenum) | |
| return E_POINTER; | |
| return create_drivecoll_enum(This, ppenum); | |
| } | |
| static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count) | |
| { | |
| struct drivecollection *This = impl_from_IDriveCollection(iface); | |
| TRACE("(%p)->(%p)\n", This, count); | |
| if (!count) return E_POINTER; | |
| *count = This->count; | |
| return S_OK; | |
| } | |
| static const IDriveCollectionVtbl drivecollectionvtbl = { | |
| drivecoll_QueryInterface, | |
| drivecoll_AddRef, | |
| drivecoll_Release, | |
| drivecoll_GetTypeInfoCount, | |
| drivecoll_GetTypeInfo, | |
| drivecoll_GetIDsOfNames, | |
| drivecoll_Invoke, | |
| drivecoll_get_Item, | |
| drivecoll_get__NewEnum, | |
| drivecoll_get_Count | |
| }; | |
| static HRESULT create_drivecoll(IDriveCollection **drives) | |
| { | |
| struct drivecollection *This; | |
| DWORD mask; | |
| *drives = NULL; | |
| This = heap_alloc(sizeof(*This)); | |
| if (!This) return E_OUTOFMEMORY; | |
| This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl; | |
| This->ref = 1; | |
| This->drives = mask = GetLogicalDrives(); | |
| /* count set bits */ | |
| for (This->count = 0; mask; This->count++) | |
| mask &= mask - 1; | |
| init_classinfo(&CLSID_Drives, (IUnknown *)&This->IDriveCollection_iface, &This->classinfo); | |
| *drives = &This->IDriveCollection_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 = &This->IFolder_iface; | |
| } | |
| else if (IsEqualIID( riid, &IID_IProvideClassInfo )) | |
| { | |
| *obj = &This->classinfo.IProvideClassInfo_iface; | |
| } | |
| else | |
| return E_NOINTERFACE; | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| 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); | |
| TRACE("(%p)->(%p)\n", This, path); | |
| if(!path) | |
| return E_POINTER; | |
| *path = SysAllocString(This->path); | |
| return *path ? S_OK : E_OUTOFMEMORY; | |
| } | |
| static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name) | |
| { | |
| struct folder *This = impl_from_IFolder(iface); | |
| WCHAR *ptr; | |
| TRACE("(%p)->(%p)\n", This, name); | |
| if(!name) | |
| return E_POINTER; | |
| *name = NULL; | |
| ptr = strrchrW(This->path, '\\'); | |
| if (ptr) | |
| { | |
| *name = SysAllocString(ptr+1); | |
| TRACE("%s\n", debugstr_w(*name)); | |
| if (!*name) return E_OUTOFMEMORY; | |
| } | |
| else | |
| return E_FAIL; | |
| return S_OK; | |
| } | |
| 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); | |
| TRACE("(%p)->(%p)\n", This, files); | |
| if(!files) | |
| return E_POINTER; | |
| return create_filecoll(This->path, files); | |
| } | |
| 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 | |
| }; | |
| HRESULT create_folder(const WCHAR *path, IFolder **folder) | |
| { | |
| struct folder *This; | |
| *folder = NULL; | |
| TRACE("%s\n", debugstr_w(path)); | |
| 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; | |
| } | |
| init_classinfo(&CLSID_Folder, (IUnknown *)&This->IFolder_iface, &This->classinfo); | |
| *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); | |
| *obj = NULL; | |
| if (IsEqualIID(riid, &IID_IFile) || | |
| IsEqualIID(riid, &IID_IDispatch) || | |
| IsEqualIID(riid, &IID_IUnknown)) | |
| { | |
| *obj = &This->IFile_iface; | |
| } | |
| else if (IsEqualIID( riid, &IID_IProvideClassInfo )) | |
| { | |
| *obj = &This->classinfo.IProvideClassInfo_iface; | |
| } | |
| else | |
| return E_NOINTERFACE; | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| return S_OK; | |
| } | |
| 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); | |
| heap_free(This); | |
| } | |
| 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 *path) | |
| { | |
| struct file *This = impl_from_IFile(iface); | |
| TRACE("(%p)->(%p)\n", This, path); | |
| if (!path) | |
| return E_POINTER; | |
| *path = SysAllocString(This->path); | |
| if (!*path) | |
| return E_OUTOFMEMORY; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name) | |
| { | |
| struct file *This = impl_from_IFile(iface); | |
| WCHAR *ptr; | |
| TRACE("(%p)->(%p)\n", This, name); | |
| if(!name) | |
| return E_POINTER; | |
| *name = NULL; | |
| ptr = strrchrW(This->path, '\\'); | |
| if (ptr) | |
| { | |
| *name = SysAllocString(ptr+1); | |
| TRACE("%s\n", debugstr_w(*name)); | |
| if (!*name) return E_OUTOFMEMORY; | |
| } | |
| else | |
| return E_FAIL; | |
| return S_OK; | |
| } | |
| 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); | |
| TRACE("(%p)->(%x)\n", This, pfa); | |
| return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError()); | |
| } | |
| static HRESULT get_date_from_filetime(const FILETIME *ft, DATE *date) | |
| { | |
| FILETIME ftlocal; | |
| SYSTEMTIME st; | |
| if (!date) | |
| return E_POINTER; | |
| FileTimeToLocalFileTime(ft, &ftlocal); | |
| FileTimeToSystemTime(&ftlocal, &st); | |
| SystemTimeToVariantTime(&st, date); | |
| return S_OK; | |
| } | |
| 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 *date) | |
| { | |
| struct file *This = impl_from_IFile(iface); | |
| WIN32_FILE_ATTRIBUTE_DATA attrs; | |
| TRACE("(%p)->(%p)\n", This, date); | |
| if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs)) | |
| return get_date_from_filetime(&attrs.ftLastWriteTime, date); | |
| return E_FAIL; | |
| } | |
| 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); | |
| ULARGE_INTEGER size; | |
| 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); | |
| size.u.LowPart = fd.nFileSizeLow; | |
| size.u.HighPart = fd.nFileSizeHigh; | |
| return variant_from_largeint(&size, pvarSize); | |
| } | |
| 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 mode, Tristate format, ITextStream **stream) | |
| { | |
| struct file *This = impl_from_IFile(iface); | |
| TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream); | |
| if (format == TristateUseDefault) { | |
| FIXME("default format not handled, defaulting to unicode\n"); | |
| format = TristateTrue; | |
| } | |
| return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream); | |
| } | |
| 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; | |
| } | |
| 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()); | |
| } | |
| init_classinfo(&CLSID_File, (IUnknown *)&f->IFile_iface, &f->classinfo); | |
| *file = &f->IFile_iface; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject) | |
| { | |
| struct filesystem *This = impl_from_IFileSystem3(iface); | |
| 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 = &This->IFileSystem3_iface; | |
| } | |
| else if (IsEqualGUID( riid, &IID_IProvideClassInfo )) | |
| { | |
| *ppvObject = &This->classinfo.IProvideClassInfo_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; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppvObject); | |
| 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) | |
| { | |
| TRACE("%p %p\n", iface, ppdrives); | |
| return create_drivecoll(ppdrives); | |
| } | |
| 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] != '\\') | |
| { | |
| 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 *drive) | |
| { | |
| TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive); | |
| if (!drive) | |
| return E_POINTER; | |
| *drive = NULL; | |
| if (path && strlenW(path) > 1 && path[1] == ':') | |
| *drive = SysAllocStringLen(path, 2); | |
| return S_OK; | |
| } | |
| 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 *ext) | |
| { | |
| INT len; | |
| TRACE("%p %s %p\n", iface, debugstr_w(path), ext); | |
| *ext = NULL; | |
| len = SysStringLen(path); | |
| while (len) { | |
| if (path[len-1] == '.') { | |
| *ext = SysAllocString(&path[len]); | |
| if (!*ext) | |
| return E_OUTOFMEMORY; | |
| break; | |
| } | |
| len--; | |
| } | |
| return S_OK; | |
| } | |
| 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) | |
| { | |
| UINT len; | |
| WCHAR driveletter; | |
| TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists); | |
| if (!pfExists) return E_POINTER; | |
| *pfExists = VARIANT_FALSE; | |
| len = SysStringLen(DriveSpec); | |
| if (len >= 1) { | |
| driveletter = toupperW(DriveSpec[0]); | |
| if (driveletter >= 'A' && driveletter <= 'Z' | |
| && (len < 2 || DriveSpec[1] == ':') | |
| && (len < 3 || DriveSpec[2] == '\\')) { | |
| const WCHAR root[] = {driveletter, ':', '\\', 0}; | |
| UINT drivetype = GetDriveTypeW(root); | |
| *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE; | |
| } | |
| } | |
| return S_OK; | |
| } | |
| 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) | |
| { | |
| UINT len; | |
| HRESULT hr; | |
| WCHAR driveletter; | |
| VARIANT_BOOL drive_exists; | |
| TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive); | |
| if (!ppdrive) | |
| return E_POINTER; | |
| *ppdrive = NULL; | |
| /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */ | |
| len = SysStringLen(DriveSpec); | |
| if (!len) | |
| return E_INVALIDARG; | |
| else if (len <= 3) { | |
| driveletter = toupperW(DriveSpec[0]); | |
| if (driveletter < 'A' || driveletter > 'Z' | |
| || (len >= 2 && DriveSpec[1] != ':') | |
| || (len == 3 && DriveSpec[2] != '\\')) | |
| return E_INVALIDARG; | |
| hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists); | |
| if (FAILED(hr)) | |
| return hr; | |
| if (drive_exists == VARIANT_FALSE) | |
| return CTL_E_DEVICEUNAVAILABLE; | |
| return create_drive(driveletter, ppdrive); | |
| } else { | |
| if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\') | |
| return E_INVALIDARG; | |
| FIXME("%s not implemented yet\n", debugstr_w(DriveSpec)); | |
| 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 **folder) | |
| { | |
| WCHAR pathW[MAX_PATH]; | |
| DWORD ret; | |
| TRACE("%p %d %p\n", iface, SpecialFolder, folder); | |
| if (!folder) | |
| return E_POINTER; | |
| *folder = NULL; | |
| switch (SpecialFolder) | |
| { | |
| case WindowsFolder: | |
| ret = GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR)); | |
| break; | |
| case SystemFolder: | |
| ret = GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR)); | |
| break; | |
| case TemporaryFolder: | |
| ret = GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW); | |
| /* we don't want trailing backslash */ | |
| if (ret && pathW[ret-1] == '\\') | |
| pathW[ret-1] = 0; | |
| break; | |
| default: | |
| FIXME("unknown special folder type, %d\n", SpecialFolder); | |
| return E_INVALIDARG; | |
| } | |
| if (!ret) | |
| return HRESULT_FROM_WIN32(GetLastError()); | |
| return create_folder(pathW, folder); | |
| } | |
| 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) { | |
| FindClose(f); | |
| 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; | |
| } | |
| } | |
| FindClose(f); | |
| 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 **stream) | |
| { | |
| DWORD disposition; | |
| TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream); | |
| disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW; | |
| return create_textstream(filename, disposition, ForWriting, !!unicode, stream); | |
| } | |
| static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename, | |
| IOMode mode, VARIANT_BOOL create, | |
| Tristate format, ITextStream **stream) | |
| { | |
| DWORD disposition; | |
| TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream); | |
| disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING; | |
| if (format == TristateUseDefault) { | |
| FIXME("default format not handled, defaulting to unicode\n"); | |
| format = TristateTrue; | |
| } | |
| return create_textstream(filename, disposition, mode, format == TristateTrue, 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); | |
| if (!ret) | |
| { | |
| heap_free(ptr); | |
| return HRESULT_FROM_WIN32(GetLastError()); | |
| } | |
| get_versionstring(info, ver); | |
| heap_free(ptr); | |
| *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 struct filesystem filesystem; | |
| HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) | |
| { | |
| TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); | |
| filesystem.IFileSystem3_iface.lpVtbl = &filesys_vtbl; | |
| init_classinfo(&CLSID_FileSystemObject, (IUnknown *)&filesystem.IFileSystem3_iface, &filesystem.classinfo); | |
| return IFileSystem3_QueryInterface(&filesystem.IFileSystem3_iface, riid, ppv); | |
| } |