mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-01 15:17:59 +00:00
4c04fb00f0
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51971 Signed-off-by: Robert Wilhelm <robert.wilhelm@gmx.net> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
4004 lines
106 KiB
C
4004 lines
106 KiB
C
/*
|
|
* Copyright 2012 Alistair Leslie-Hughes
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#define COBJMACROS
|
|
|
|
#include <stdarg.h>
|
|
#include <limits.h>
|
|
#include <assert.h>
|
|
#include <wchar.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/heap.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
|
|
|
|
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;
|
|
WCHAR root[4];
|
|
};
|
|
|
|
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;
|
|
LARGE_INTEGER size;
|
|
HANDLE file;
|
|
|
|
BOOL eof;
|
|
WCHAR *read_buf;
|
|
size_t read_buf_size;
|
|
};
|
|
|
|
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 HRESULT create_drivecoll_enum(struct drivecollection*, IUnknown**);
|
|
|
|
static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
|
|
{
|
|
return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
|
wcscmp(data->cFileName, L"..") &&
|
|
wcscmp(data->cFileName, L".");
|
|
}
|
|
|
|
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];
|
|
|
|
lstrcpyW(buffW, path);
|
|
if (path[len-1] != '\\') wcscat(buffW, L"\\");
|
|
lstrcatW(buffW, data->cFileName);
|
|
|
|
return SysAllocString(buffW);
|
|
}
|
|
|
|
static HRESULT build_path( BSTR Path, BSTR Name, BSTR *Result)
|
|
{
|
|
BSTR ret;
|
|
|
|
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)
|
|
{
|
|
lstrcpyW(ret, Path);
|
|
ret[path_len] = 0;
|
|
lstrcatW(ret, Name);
|
|
}
|
|
}
|
|
else if (Path[path_len-1] != '\\' && Name[0] != '\\')
|
|
{
|
|
ret = SysAllocStringLen(NULL, path_len + name_len + 1);
|
|
if (ret)
|
|
{
|
|
lstrcpyW(ret, Path);
|
|
if (Path[path_len-1] != ':')
|
|
wcscat(ret, L"\\");
|
|
lstrcatW(ret, Name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = SysAllocStringLen(NULL, path_len + name_len);
|
|
if (ret)
|
|
{
|
|
lstrcpyW(ret, Path);
|
|
lstrcatW(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 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)
|
|
{
|
|
if (This->read_buf_size) heap_free(This->read_buf);
|
|
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);
|
|
|
|
TRACE("(%p)->(%p)\n", This, eos);
|
|
|
|
if (!eos)
|
|
return E_POINTER;
|
|
|
|
if (textstream_check_iomode(This, IORead)) {
|
|
*eos = VARIANT_TRUE;
|
|
return CTL_E_BADFILEMODE;
|
|
}
|
|
|
|
*eos = (This->eof && !This->read_buf_size) ? 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;
|
|
}
|
|
|
|
static HRESULT append_read_data(struct textstream *stream, const char *buf, size_t buf_size)
|
|
{
|
|
LARGE_INTEGER revert;
|
|
size_t len;
|
|
WCHAR *new_buf;
|
|
|
|
revert.QuadPart = 0;
|
|
if (stream->unicode)
|
|
{
|
|
len = buf_size / sizeof(WCHAR);
|
|
if (buf_size & 1) revert.QuadPart = -1;
|
|
}
|
|
else
|
|
{
|
|
for (len = 0; len < buf_size; len++)
|
|
{
|
|
if (!IsDBCSLeadByte(buf[len])) continue;
|
|
if (len + 1 == buf_size)
|
|
{
|
|
revert.QuadPart = -1;
|
|
buf_size--;
|
|
break;
|
|
}
|
|
len++;
|
|
}
|
|
len = MultiByteToWideChar(CP_ACP, 0, buf, buf_size, NULL, 0);
|
|
}
|
|
if (!len)
|
|
return S_OK;
|
|
if (revert.QuadPart)
|
|
SetFilePointerEx(stream->file, revert, NULL, FILE_CURRENT);
|
|
|
|
if (!stream->read_buf_size)
|
|
new_buf = heap_alloc(len * sizeof(WCHAR));
|
|
else
|
|
new_buf = heap_realloc(stream->read_buf, (len + stream->read_buf_size) * sizeof(WCHAR));
|
|
if (!new_buf) return E_OUTOFMEMORY;
|
|
|
|
if (stream->unicode)
|
|
memcpy(new_buf + stream->read_buf_size, buf, len * sizeof(WCHAR));
|
|
else
|
|
MultiByteToWideChar(CP_ACP, 0, buf, buf_size, new_buf + stream->read_buf_size, len);
|
|
stream->read_buf = new_buf;
|
|
stream->read_buf_size += len;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT read_more_data(struct textstream *stream)
|
|
{
|
|
char buf[256];
|
|
DWORD read;
|
|
|
|
if (stream->eof) return S_OK;
|
|
|
|
if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
|
|
{
|
|
ITextStream_Release(&stream->ITextStream_iface);
|
|
return create_error(GetLastError());
|
|
}
|
|
|
|
stream->eof = read != sizeof(buf);
|
|
return append_read_data(stream, buf, read);
|
|
}
|
|
|
|
static BOOL read_from_buffer(struct textstream *stream, size_t len, BSTR *ret, size_t skip)
|
|
{
|
|
assert(len + skip <= stream->read_buf_size);
|
|
|
|
if (!(*ret = SysAllocStringLen(stream->read_buf, len))) return FALSE;
|
|
|
|
len += skip;
|
|
stream->read_buf_size -= len;
|
|
if (stream->read_buf_size)
|
|
memmove(stream->read_buf, stream->read_buf + len, stream->read_buf_size * sizeof(WCHAR));
|
|
else
|
|
heap_free(stream->read_buf);
|
|
return TRUE;
|
|
}
|
|
|
|
static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
|
|
{
|
|
struct textstream *This = impl_from_ITextStream(iface);
|
|
HRESULT hr = S_OK;
|
|
|
|
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;
|
|
|
|
while (!This->eof && len > This->read_buf_size)
|
|
{
|
|
if (FAILED(hr = read_more_data(This)))
|
|
return hr;
|
|
}
|
|
|
|
if (This->eof && !This->read_buf_size)
|
|
return CTL_E_ENDOFFILE;
|
|
|
|
if (len > This->read_buf_size)
|
|
{
|
|
len = This->read_buf_size;
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return read_from_buffer(This, len, text, 0) ? hr : E_OUTOFMEMORY;
|
|
}
|
|
|
|
static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
|
|
{
|
|
struct textstream *This = impl_from_ITextStream(iface);
|
|
unsigned int skip = 0;
|
|
const WCHAR *nl;
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE("(%p)->(%p)\n", This, text);
|
|
|
|
if (!text)
|
|
return E_POINTER;
|
|
|
|
*text = NULL;
|
|
if (textstream_check_iomode(This, IORead))
|
|
return CTL_E_BADFILEMODE;
|
|
|
|
while (!(nl = wmemchr(This->read_buf, '\n', This->read_buf_size)) && !This->eof)
|
|
{
|
|
if (FAILED(hr = read_more_data(This)))
|
|
return hr;
|
|
}
|
|
|
|
if (This->eof && !This->read_buf_size)
|
|
return CTL_E_ENDOFFILE;
|
|
|
|
if (!nl)
|
|
{
|
|
nl = This->read_buf + This->read_buf_size;
|
|
hr = S_FALSE;
|
|
}
|
|
else if (nl > This->read_buf && nl[-1] == '\r')
|
|
{
|
|
nl--;
|
|
skip = 2;
|
|
}
|
|
else skip = 1;
|
|
|
|
return read_from_buffer(This, nl - This->read_buf, text, skip) ? hr : E_OUTOFMEMORY;
|
|
}
|
|
|
|
static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
|
|
{
|
|
struct textstream *This = impl_from_ITextStream(iface);
|
|
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;
|
|
|
|
while (!This->eof)
|
|
{
|
|
if (FAILED(hr = read_more_data(This)))
|
|
return hr;
|
|
}
|
|
|
|
if (This->eof && !This->read_buf_size)
|
|
return CTL_E_ENDOFFILE;
|
|
|
|
return read_from_buffer(This, This->read_buf_size, text, 0) ? S_FALSE : E_OUTOFMEMORY;
|
|
}
|
|
|
|
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, Tristate format, ITextStream **ret)
|
|
{
|
|
static const unsigned short utf16bom = 0xfeff;
|
|
struct textstream *stream;
|
|
DWORD access = 0;
|
|
HRESULT hr;
|
|
|
|
/* map access mode */
|
|
switch (mode)
|
|
{
|
|
case ForReading:
|
|
access = GENERIC_READ;
|
|
break;
|
|
case ForWriting:
|
|
access = GENERIC_WRITE;
|
|
break;
|
|
case ForAppending:
|
|
access = GENERIC_READ | GENERIC_WRITE;
|
|
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->eof = FALSE;
|
|
stream->read_buf = NULL;
|
|
stream->read_buf_size = 0;
|
|
|
|
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;
|
|
|
|
if (mode == ForWriting)
|
|
{
|
|
stream->unicode = format == TristateTrue;
|
|
/* Write Unicode BOM */
|
|
if (stream->unicode && (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());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD read, buf_offset = 0;
|
|
BYTE buf[64];
|
|
|
|
if (format == TristateUseDefault || mode == ForReading)
|
|
{
|
|
if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
|
|
{
|
|
ITextStream_Release(&stream->ITextStream_iface);
|
|
return create_error(GetLastError());
|
|
}
|
|
}
|
|
|
|
if (format == TristateUseDefault)
|
|
stream->unicode = IsTextUnicode(buf, read, NULL);
|
|
else
|
|
stream->unicode = format != TristateFalse;
|
|
|
|
if (mode == ForReading)
|
|
{
|
|
if (stream->unicode && read >= 2 && buf[0] == 0xff && buf[1] == 0xfe)
|
|
buf_offset += 2; /* skip utf16 BOM */
|
|
|
|
hr = append_read_data(stream, (const char *)buf + buf_offset, read - buf_offset);
|
|
if (FAILED(hr))
|
|
{
|
|
ITextStream_Release(&stream->ITextStream_iface);
|
|
return hr;
|
|
}
|
|
|
|
stream->eof = read != sizeof(buf);
|
|
}
|
|
else SetFilePointer(stream->file, 0, 0, FILE_END);
|
|
}
|
|
|
|
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)
|
|
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, ARRAY_SIZE(nameW), 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, ARRAY_SIZE(nameW));
|
|
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 *object;
|
|
|
|
*drive = NULL;
|
|
|
|
object = heap_alloc(sizeof(*object));
|
|
if (!object) return E_OUTOFMEMORY;
|
|
|
|
object->IDrive_iface.lpVtbl = &drivevtbl;
|
|
object->ref = 1;
|
|
wcscpy(object->root, L"A:\\");
|
|
*object->root = letter;
|
|
|
|
init_classinfo(&CLSID_Drive, (IUnknown *)&object->IDrive_iface, &object->classinfo);
|
|
*drive = &object->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)
|
|
{
|
|
WCHAR pathW[MAX_PATH];
|
|
int len;
|
|
HANDLE handle;
|
|
|
|
lstrcpyW(pathW, path);
|
|
len = lstrlenW(pathW);
|
|
if (len && pathW[len-1] != '\\') wcscat(pathW, L"\\");
|
|
wcscat(pathW, L"*");
|
|
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);
|
|
TRACE("(%p)->(%p)\n", This, pclone);
|
|
return create_drivecoll_enum(This->data.u.drivecoll.coll, (IUnknown**)pclone);
|
|
}
|
|
|
|
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);
|
|
WIN32_FIND_DATAW data;
|
|
WCHAR pathW[MAX_PATH];
|
|
HANDLE handle;
|
|
|
|
TRACE("(%p)->(%p)\n", This, count);
|
|
|
|
if(!count)
|
|
return E_POINTER;
|
|
|
|
*count = 0;
|
|
|
|
wcscpy(pathW, This->path);
|
|
wcscat(pathW, L"\\*");
|
|
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);
|
|
WIN32_FIND_DATAW data;
|
|
WCHAR pathW[MAX_PATH];
|
|
HANDLE handle;
|
|
|
|
TRACE("(%p)->(%p)\n", This, count);
|
|
|
|
if(!count)
|
|
return E_POINTER;
|
|
|
|
*count = 0;
|
|
|
|
wcscpy(pathW, This->path);
|
|
wcscat(pathW, L"\\*");
|
|
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 = wcsrchr(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)
|
|
{
|
|
DWORD disposition;
|
|
BSTR path;
|
|
HRESULT hres;
|
|
|
|
struct folder *This = impl_from_IFolder(iface);
|
|
|
|
TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
|
|
|
|
hres = build_path(This->path, filename, &path);
|
|
if (FAILED(hres)) return hres;
|
|
|
|
disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
|
|
hres = create_textstream(path, disposition, ForWriting, unicode ? TristateTrue : TristateFalse, stream);
|
|
SysFreeString(path);
|
|
return hres;
|
|
}
|
|
|
|
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 = wcsrchr(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);
|
|
|
|
return create_textstream(This->path, OPEN_EXISTING, mode, format, 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)
|
|
{
|
|
TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
|
|
|
|
if (!Result) return E_POINTER;
|
|
|
|
return build_path(Path, Name, Result);
|
|
}
|
|
|
|
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 && lstrlenW(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=lstrlenW(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=lstrlenW(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)
|
|
{
|
|
WCHAR buf[MAX_PATH], ch;
|
|
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;
|
|
|
|
len = GetFullPathNameW(path ? path : L".", MAX_PATH, buf, NULL);
|
|
if(!len)
|
|
return E_FAIL;
|
|
|
|
buf[0] = towupper(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 = lstrlenW(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 *result)
|
|
{
|
|
DWORD random;
|
|
|
|
TRACE("%p, %p.\n", iface, result);
|
|
|
|
if (!result)
|
|
return E_POINTER;
|
|
|
|
if (!(*result = SysAllocStringLen(NULL, 12)))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if(!RtlGenRandom(&random, sizeof(random)))
|
|
return E_FAIL;
|
|
swprintf(*result, 12, L"rad%05X.txt", 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 = towupper(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 = towupper(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, ARRAY_SIZE(pathW));
|
|
break;
|
|
case SystemFolder:
|
|
ret = GetSystemDirectoryW(pathW, ARRAY_SIZE(pathW));
|
|
break;
|
|
case TemporaryFolder:
|
|
ret = GetTempPathW(ARRAY_SIZE(pathW), 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 = lstrlenW(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 = lstrlenW(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)
|
|
{
|
|
TRACE("%p %s %s\n", iface, debugstr_w(source), debugstr_w(destination));
|
|
|
|
return MoveFileW(source, destination) ? S_OK : create_error(GetLastError());
|
|
}
|
|
|
|
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 = lstrlenW(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 = lstrlenW(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 ? TristateTrue : TristateFalse, 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;
|
|
return create_textstream(filename, disposition, mode, format, 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)
|
|
{
|
|
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);
|
|
|
|
swprintf(ver, 30, L"%d.%d.%d.%d", a, b, c, d);
|
|
}
|
|
|
|
static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
|
|
{
|
|
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, L"\\", (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);
|
|
}
|