[SCRRUN]
authorAmine Khaldi <amine.khaldi@reactos.org>
Thu, 24 Apr 2014 16:00:09 +0000 (16:00 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Thu, 24 Apr 2014 16:00:09 +0000 (16:00 +0000)
* Sync with Wine 1.7.17.
CORE-8080

svn path=/trunk/; revision=62953

reactos/dll/win32/scrrun/filesystem.c
reactos/dll/win32/scrrun/scrrun.c
reactos/dll/win32/scrrun/scrrun.idl
reactos/dll/win32/scrrun/scrrun_private.h
reactos/dll/win32/scrrun/scrrun_tlb.rgs
reactos/media/doc/README.WINE

index 9dcace6..d22bb1f 100644 (file)
 #include <ntsecapi.h>
 #include <wine/unicode.h>
 
+static const WCHAR bsW[] = {'\\',0};
+static const WCHAR utf16bom = 0xfeff;
+
+struct foldercollection {
+    IFolderCollection IFolderCollection_iface;
+    LONG ref;
+    BSTR path;
+};
+
+struct filecollection {
+    IFileCollection IFileCollection_iface;
+    LONG ref;
+    BSTR path;
+};
+
+struct drivecollection {
+    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 {
+    IDrive IDrive_iface;
+    LONG ref;
+    BSTR root;
+};
+
 struct folder {
     IFolder IFolder_iface;
     LONG ref;
+    BSTR path;
 };
 
 struct file {
@@ -40,6 +97,10 @@ struct textstream {
     LONG ref;
 
     IOMode mode;
+    BOOL unicode;
+    BOOL first_read;
+    LARGE_INTEGER size;
+    HANDLE file;
 };
 
 enum iotype {
@@ -47,6 +108,11 @@ enum iotype {
     IOWrite
 };
 
+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);
@@ -62,6 +128,26 @@ 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) {
@@ -74,46 +160,1735 @@ static inline HRESULT create_error(DWORD err)
         FIXME("Unsupported error code: %d\n", err);
         return E_FAIL;
     }
-}
+}
+
+static HRESULT create_folder(const WCHAR*, IFolder**);
+static HRESULT create_file(BSTR, IFile**);
+static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
+static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
+
+static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
+{
+    static const WCHAR dotdotW[] = {'.','.',0};
+    static const WCHAR dotW[] = {'.',0};
+
+    return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+            strcmpW(data->cFileName, dotdotW) &&
+            strcmpW(data->cFileName, dotW);
+}
+
+static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
+{
+    return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+}
+
+static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
+{
+    int len = SysStringLen(path);
+    WCHAR buffW[MAX_PATH];
+
+    strcpyW(buffW, path);
+    if (path[len-1] != '\\')
+        strcatW(buffW, bsW);
+    strcatW(buffW, data->cFileName);
+
+    return SysAllocString(buffW);
+}
+
+static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
+{
+    if (type == IORead)
+        return This->mode == ForWriting || This->mode == ForAppending;
+    else
+        return This->mode == ForReading;
+}
+
+static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+
+    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+
+    if (IsEqualIID(riid, &IID_ITextStream) ||
+        IsEqualIID(riid, &IID_IDispatch) ||
+        IsEqualIID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        ITextStream_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI textstream_AddRef(ITextStream *iface)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p)->(%d)\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI textstream_Release(ITextStream *iface)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+    TRACE("(%p)->(%d)\n", This, ref);
+
+    if (!ref)
+    {
+        CloseHandle(This->file);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    TRACE("(%p)->(%p)\n", This, pctinfo);
+    *pctinfo = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
+                                        LCID lcid, ITypeInfo **ppTInfo)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
+    return get_typeinfo(ITextStream_tid, ppTInfo);
+}
+
+static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
+                                        LPOLESTR *rgszNames, UINT cNames,
+                                        LCID lcid, DISPID *rgDispId)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+    hr = get_typeinfo(ITextStream_tid, &typeinfo);
+    if(SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
+                                      REFIID riid, LCID lcid, WORD wFlags,
+                                      DISPPARAMS *pDispParams, VARIANT *pVarResult,
+                                      EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
+           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    hr = get_typeinfo(ITextStream_tid, &typeinfo);
+    if(SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
+                pDispParams, pVarResult, pExcepInfo, puArgErr);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    FIXME("(%p)->(%p): stub\n", This, line);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    FIXME("(%p)->(%p): stub\n", This, column);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    LARGE_INTEGER pos, dist;
+
+    TRACE("(%p)->(%p)\n", This, eos);
+
+    if (!eos)
+        return E_POINTER;
+
+    if (textstream_check_iomode(This, IORead)) {
+        *eos = VARIANT_TRUE;
+        return CTL_E_BADFILEMODE;
+    }
+
+    dist.QuadPart = 0;
+    if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
+        return E_FAIL;
+
+    *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
+    return S_OK;
+}
+
+static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    FIXME("(%p)->(%p): stub\n", This, eol);
+    return E_NOTIMPL;
+}
+
+/*
+   Reads 'toread' bytes from a file, converts if needed
+   BOM is skipped if 'bof' is set.
+ */
+static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text)
+{
+    HRESULT hr = S_OK;
+    DWORD read;
+    char *buff;
+    BOOL ret;
+
+    if (toread == 0) {
+        *text = SysAllocStringLen(NULL, 0);
+        return *text ? S_FALSE : E_OUTOFMEMORY;
+    }
+
+    if (toread < sizeof(WCHAR))
+        return CTL_E_ENDOFFILE;
+
+    buff = heap_alloc(toread);
+    if (!buff)
+        return E_OUTOFMEMORY;
+
+    ret = ReadFile(stream->file, buff, toread, &read, NULL);
+    if (!ret || toread != read) {
+        WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError());
+        heap_free(buff);
+        return E_FAIL;
+    }
+
+    if (stream->unicode) {
+        int i = 0;
+
+        /* skip BOM */
+        if (bof && *(WCHAR*)buff == utf16bom) {
+            read -= sizeof(WCHAR);
+            i += sizeof(WCHAR);
+        }
+
+        *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR));
+        if (!*text) hr = E_OUTOFMEMORY;
+    }
+    else {
+        INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0);
+        *text = SysAllocStringLen(NULL, len);
+        if (*text)
+            MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len);
+        else
+            hr = E_OUTOFMEMORY;
+    }
+    heap_free(buff);
+
+    return hr;
+}
+
+static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    LARGE_INTEGER start, end, dist;
+    DWORD toread;
+    HRESULT hr;
+
+    TRACE("(%p)->(%d %p)\n", This, len, text);
+
+    if (!text)
+        return E_POINTER;
+
+    *text = NULL;
+    if (len <= 0)
+        return len == 0 ? S_OK : E_INVALIDARG;
+
+    if (textstream_check_iomode(This, IORead))
+        return CTL_E_BADFILEMODE;
+
+    if (!This->first_read) {
+        VARIANT_BOOL eos;
+
+        /* check for EOF */
+        hr = ITextStream_get_AtEndOfStream(iface, &eos);
+        if (FAILED(hr))
+            return hr;
+
+        if (eos == VARIANT_TRUE)
+            return CTL_E_ENDOFFILE;
+    }
+
+    /* read everything from current position */
+    dist.QuadPart = 0;
+    SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
+    SetFilePointerEx(This->file, dist, &end, FILE_END);
+    toread = end.QuadPart - start.QuadPart;
+    /* rewind back */
+    dist.QuadPart = start.QuadPart;
+    SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
+
+    This->first_read = FALSE;
+    if (This->unicode) len *= sizeof(WCHAR);
+
+    hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
+    if (FAILED(hr))
+        return hr;
+    else
+        return toread <= len ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    VARIANT_BOOL eos;
+    HRESULT hr;
+
+    FIXME("(%p)->(%p): stub\n", This, text);
+
+    if (!text)
+        return E_POINTER;
+
+    *text = NULL;
+    if (textstream_check_iomode(This, IORead))
+        return CTL_E_BADFILEMODE;
+
+    /* check for EOF */
+    hr = ITextStream_get_AtEndOfStream(iface, &eos);
+    if (FAILED(hr))
+        return hr;
+
+    if (eos == VARIANT_TRUE)
+        return CTL_E_ENDOFFILE;
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    LARGE_INTEGER start, end, dist;
+    DWORD toread;
+    HRESULT hr;
+
+    TRACE("(%p)->(%p)\n", This, text);
+
+    if (!text)
+        return E_POINTER;
+
+    *text = NULL;
+    if (textstream_check_iomode(This, IORead))
+        return CTL_E_BADFILEMODE;
+
+    if (!This->first_read) {
+        VARIANT_BOOL eos;
+
+        /* check for EOF */
+        hr = ITextStream_get_AtEndOfStream(iface, &eos);
+        if (FAILED(hr))
+            return hr;
+
+        if (eos == VARIANT_TRUE)
+            return CTL_E_ENDOFFILE;
+    }
+
+    /* read everything from current position */
+    dist.QuadPart = 0;
+    SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
+    SetFilePointerEx(This->file, dist, &end, FILE_END);
+    toread = end.QuadPart - start.QuadPart;
+    /* rewind back */
+    dist.QuadPart = start.QuadPart;
+    SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
+
+    This->first_read = FALSE;
+
+    hr = textstream_read(This, toread, start.QuadPart == 0, text);
+    return FAILED(hr) ? hr : S_FALSE;
+}
+
+static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
+{
+    DWORD written = 0;
+    BOOL ret;
+
+    if (stream->unicode) {
+        ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
+        return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
+    } else {
+        DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
+        char *buffA;
+        HRESULT hr;
+
+        buffA = heap_alloc(len);
+        if (!buffA)
+            return E_OUTOFMEMORY;
+
+        WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
+        ret = WriteFile(stream->file, buffA, len, &written, NULL);
+        hr = (ret && written == len) ? S_OK : create_error(GetLastError());
+        heap_free(buffA);
+        return hr;
+    }
+}
+
+static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(text));
+
+    if (textstream_check_iomode(This, IOWrite))
+        return CTL_E_BADFILEMODE;
+
+    return textstream_writestr(This, text);
+}
+
+static HRESULT textstream_writecrlf(struct textstream *stream)
+{
+    static const WCHAR crlfW[] = {'\r','\n'};
+    static const char crlfA[] = {'\r','\n'};
+    DWORD written = 0, len;
+    const void *ptr;
+    BOOL ret;
+
+    if (stream->unicode) {
+        ptr = crlfW;
+        len = sizeof(crlfW);
+    }
+    else {
+        ptr = crlfA;
+        len = sizeof(crlfA);
+    }
+
+    ret = WriteFile(stream->file, ptr, len, &written, NULL);
+    return (ret && written == len) ? S_OK : create_error(GetLastError());
+}
+
+static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    HRESULT hr;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(text));
+
+    if (textstream_check_iomode(This, IOWrite))
+        return CTL_E_BADFILEMODE;
+
+    hr = textstream_writestr(This, text);
+    if (SUCCEEDED(hr))
+        hr = textstream_writecrlf(This);
+    return hr;
+}
+
+static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    FIXME("(%p)->(%d): stub\n", This, lines);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    FIXME("(%p)->(%d): stub\n", This, count);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    FIXME("(%p): stub\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI textstream_Close(ITextStream *iface)
+{
+    struct textstream *This = impl_from_ITextStream(iface);
+    FIXME("(%p): stub\n", This);
+    return E_NOTIMPL;
+}
+
+static const ITextStreamVtbl textstreamvtbl = {
+    textstream_QueryInterface,
+    textstream_AddRef,
+    textstream_Release,
+    textstream_GetTypeInfoCount,
+    textstream_GetTypeInfo,
+    textstream_GetIDsOfNames,
+    textstream_Invoke,
+    textstream_get_Line,
+    textstream_get_Column,
+    textstream_get_AtEndOfStream,
+    textstream_get_AtEndOfLine,
+    textstream_Read,
+    textstream_ReadLine,
+    textstream_ReadAll,
+    textstream_Write,
+    textstream_WriteLine,
+    textstream_WriteBlankLines,
+    textstream_Skip,
+    textstream_SkipLine,
+    textstream_Close
+};
+
+static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
+{
+    struct textstream *stream;
+    DWORD access = 0;
+
+    /* map access mode */
+    switch (mode)
+    {
+    case ForReading:
+        access = GENERIC_READ;
+        break;
+    case ForWriting:
+        access = GENERIC_WRITE;
+        break;
+    case ForAppending:
+        access = FILE_APPEND_DATA;
+        break;
+    default:
+        return E_INVALIDARG;
+    }
+
+    stream = heap_alloc(sizeof(struct textstream));
+    if (!stream) return E_OUTOFMEMORY;
+
+    stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
+    stream->ref = 1;
+    stream->mode = mode;
+    stream->unicode = unicode;
+    stream->first_read = TRUE;
+
+    stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (stream->file == INVALID_HANDLE_VALUE)
+    {
+        HRESULT hr = create_error(GetLastError());
+        heap_free(stream);
+        return hr;
+    }
+
+    if (mode == ForReading)
+        GetFileSizeEx(stream->file, &stream->size);
+    else
+        stream->size.QuadPart = 0;
+
+    /* Write Unicode BOM */
+    if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
+        DWORD written = 0;
+        BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
+        if (!ret || written != sizeof(utf16bom)) {
+            ITextStream_Release(&stream->ITextStream_iface);
+            return create_error(GetLastError());
+        }
+    }
+
+    *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 = iface;
+        IDrive_AddRef(iface);
+    }
+    else
+        return E_NOINTERFACE;
+
+    return S_OK;
+}
+
+static ULONG WINAPI drive_AddRef(IDrive *iface)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p)->(%d)\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI drive_Release(IDrive *iface)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+    TRACE("(%p)->(%d)\n", This, ref);
+
+    if (!ref)
+    {
+        SysFreeString(This->root);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    TRACE("(%p)->(%p)\n", This, pctinfo);
+    *pctinfo = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
+                                        LCID lcid, ITypeInfo **ppTInfo)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
+    return get_typeinfo(IDrive_tid, ppTInfo);
+}
+
+static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
+                                        LPOLESTR *rgszNames, UINT cNames,
+                                        LCID lcid, DISPID *rgDispId)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+    hr = get_typeinfo(IDrive_tid, &typeinfo);
+    if(SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
+                                      REFIID riid, LCID lcid, WORD wFlags,
+                                      DISPPARAMS *pDispParams, VARIANT *pVarResult,
+                                      EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
+           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    hr = get_typeinfo(IDrive_tid, &typeinfo);
+    if(SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
+                pDispParams, pVarResult, pExcepInfo, puArgErr);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    FIXME("(%p)->(%p): stub\n", This, path);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
+{
+    struct drive *This = impl_from_IDrive(iface);
+
+    TRACE("(%p)->(%p)\n", This, letter);
+
+    if (!letter)
+        return E_POINTER;
+
+    *letter = SysAllocStringLen(This->root, 1);
+    if (!*letter)
+        return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    FIXME("(%p)->(%p): stub\n", This, share_name);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
+{
+    struct drive *This = impl_from_IDrive(iface);
+
+    TRACE("(%p)->(%p)\n", This, type);
+
+    switch (GetDriveTypeW(This->root))
+    {
+    case DRIVE_REMOVABLE:
+        *type = Removable;
+        break;
+    case DRIVE_FIXED:
+        *type = Fixed;
+        break;
+    case DRIVE_REMOTE:
+        *type = Remote;
+        break;
+    case DRIVE_CDROM:
+        *type = CDRom;
+        break;
+    case DRIVE_RAMDISK:
+        *type = RamDisk;
+        break;
+    default:
+        *type = UnknownType;
+        break;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    FIXME("(%p)->(%p): stub\n", This, folder);
+    return E_NOTIMPL;
+}
+
+static HRESULT 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;
+
+    V_VT(v) = VT_R8;
+    return VarR8FromUI8(avail.QuadPart, &V_R8(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;
+
+    V_VT(v) = VT_R8;
+    return VarR8FromUI8(freespace.QuadPart, &V_R8(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;
+
+    V_VT(v) = VT_R8;
+    return VarR8FromUI8(total.QuadPart, &V_R8(v));
+}
+
+static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    FIXME("(%p)->(%p): stub\n", This, name);
+    return E_NOTIMPL;
+}
+
+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);
+    FIXME("(%p)->(%p): stub\n", This, fs);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    FIXME("(%p)->(%p): stub\n", This, serial);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
+{
+    struct drive *This = impl_from_IDrive(iface);
+    ULARGE_INTEGER freespace;
+    BOOL ret;
+
+    TRACE("(%p)->(%p)\n", This, ready);
+
+    if (!ready)
+        return E_POINTER;
+
+    ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
+    *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
+    return S_OK;
+}
+
+static const IDriveVtbl drivevtbl = {
+    drive_QueryInterface,
+    drive_AddRef,
+    drive_Release,
+    drive_GetTypeInfoCount,
+    drive_GetTypeInfo,
+    drive_GetIDsOfNames,
+    drive_Invoke,
+    drive_get_Path,
+    drive_get_DriveLetter,
+    drive_get_ShareName,
+    drive_get_DriveType,
+    drive_get_RootFolder,
+    drive_get_AvailableSpace,
+    drive_get_FreeSpace,
+    drive_get_TotalSize,
+    drive_get_VolumeName,
+    drive_put_VolumeName,
+    drive_get_FileSystem,
+    drive_get_SerialNumber,
+    drive_get_IsReady
+};
+
+static HRESULT create_drive(WCHAR letter, IDrive **drive)
+{
+    struct drive *This;
+
+    *drive = NULL;
+
+    This = heap_alloc(sizeof(*This));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IDrive_iface.lpVtbl = &drivevtbl;
+    This->ref = 1;
+    This->root = SysAllocStringLen(NULL, 3);
+    if (!This->root)
+    {
+        heap_free(This);
+        return E_OUTOFMEMORY;
+    }
+    This->root[0] = letter;
+    This->root[1] = ':';
+    This->root[2] = '\\';
+    This->root[3] = 0;
+
+    *drive = &This->IDrive_iface;
+    return S_OK;
+}
+
+static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+
+    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+
+    *obj = NULL;
+
+    if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
+        IsEqualIID( riid, &IID_IUnknown ))
+    {
+        *obj = iface;
+        IEnumVARIANT_AddRef(iface);
+    }
+    else
+        return E_NOINTERFACE;
+
+    return S_OK;
+}
+
+static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p)->(%d)\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p)->(%d)\n", This, ref);
+
+    if (!ref)
+    {
+        IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
+        FindClose(This->data.u.foldercoll.find);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
+{
+    static const WCHAR allW[] = {'*',0};
+    WCHAR pathW[MAX_PATH];
+    int len;
+    HANDLE handle;
+
+    strcpyW(pathW, path);
+    len = strlenW(pathW);
+    if (pathW[len-1] != '\\')
+        strcatW(pathW, bsW);
+    strcatW(pathW, allW);
+    handle = FindFirstFileW(pathW, data);
+    if (handle == INVALID_HANDLE_VALUE) return 0;
+
+    /* find first dir/file */
+    while (1)
+    {
+        if (file ? is_file_data(data) : is_dir_data(data))
+            break;
+
+        if (!FindNextFileW(handle, data))
+        {
+            FindClose(handle);
+            return 0;
+        }
+    }
+    return handle;
+}
+
+static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    HANDLE handle = This->data.u.foldercoll.find;
+    WIN32_FIND_DATAW data;
+    ULONG count = 0;
+
+    TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
+
+    if (fetched)
+        *fetched = 0;
+
+    if (!celt) return S_OK;
+
+    if (!handle)
+    {
+        handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
+        if (!handle) return S_FALSE;
+
+        This->data.u.foldercoll.find = handle;
+    }
+    else
+    {
+        if (!FindNextFileW(handle, &data))
+            return S_FALSE;
+    }
+
+    do
+    {
+        if (is_dir_data(&data))
+        {
+            IFolder *folder;
+            HRESULT hr;
+            BSTR str;
+
+            str = get_full_path(This->data.u.foldercoll.coll->path, &data);
+            hr = create_folder(str, &folder);
+            SysFreeString(str);
+            if (FAILED(hr)) return hr;
+
+            V_VT(&var[count]) = VT_DISPATCH;
+            V_DISPATCH(&var[count]) = (IDispatch*)folder;
+            count++;
+
+            if (count >= celt) break;
+        }
+    } while (FindNextFileW(handle, &data));
+
+    if (fetched)
+        *fetched = count;
+
+    return (count < celt) ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    HANDLE handle = This->data.u.foldercoll.find;
+    WIN32_FIND_DATAW data;
+
+    TRACE("(%p)->(%d)\n", This, celt);
+
+    if (!celt) return S_OK;
+
+    if (!handle)
+    {
+        handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
+        if (!handle) return S_FALSE;
+
+        This->data.u.foldercoll.find = handle;
+    }
+    else
+    {
+        if (!FindNextFileW(handle, &data))
+            return S_FALSE;
+    }
+
+    do
+    {
+        if (is_dir_data(&data))
+            --celt;
+
+        if (!celt) break;
+    } while (FindNextFileW(handle, &data));
+
+    return celt ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+
+    TRACE("(%p)\n", This);
+
+    FindClose(This->data.u.foldercoll.find);
+    This->data.u.foldercoll.find = NULL;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    TRACE("(%p)->(%p)\n", This, pclone);
+    return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
+}
+
+static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
+    enumvariant_QueryInterface,
+    enumvariant_AddRef,
+    foldercoll_enumvariant_Release,
+    foldercoll_enumvariant_Next,
+    foldercoll_enumvariant_Skip,
+    foldercoll_enumvariant_Reset,
+    foldercoll_enumvariant_Clone
+};
+
+static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
+{
+    struct enumvariant *This;
+
+    *newenum = NULL;
+
+    This = heap_alloc(sizeof(*This));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
+    This->ref = 1;
+    This->data.u.foldercoll.find = NULL;
+    This->data.u.foldercoll.coll = collection;
+    IFolderCollection_AddRef(&collection->IFolderCollection_iface);
+
+    *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
+
+    return S_OK;
+}
+
+static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p)->(%d)\n", This, ref);
+
+    if (!ref)
+    {
+        IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
+        FindClose(This->data.u.filecoll.find);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    HANDLE handle = This->data.u.filecoll.find;
+    WIN32_FIND_DATAW data;
+    ULONG count = 0;
+
+    TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
+
+    if (fetched)
+        *fetched = 0;
+
+    if (!celt) return S_OK;
+
+    if (!handle)
+    {
+        handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
+        if (!handle) return S_FALSE;
+        This->data.u.filecoll.find = handle;
+    }
+    else if (!FindNextFileW(handle, &data))
+        return S_FALSE;
+
+    do
+    {
+        if (is_file_data(&data))
+        {
+            IFile *file;
+            HRESULT hr;
+            BSTR str;
+
+            str = get_full_path(This->data.u.filecoll.coll->path, &data);
+            hr = create_file(str, &file);
+            SysFreeString(str);
+            if (FAILED(hr)) return hr;
+
+            V_VT(&var[count]) = VT_DISPATCH;
+            V_DISPATCH(&var[count]) = (IDispatch*)file;
+            if (++count >= celt) break;
+        }
+    } while (FindNextFileW(handle, &data));
+
+    if (fetched)
+        *fetched = count;
+
+    return (count < celt) ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    HANDLE handle = This->data.u.filecoll.find;
+    WIN32_FIND_DATAW data;
+
+    TRACE("(%p)->(%d)\n", This, celt);
+
+    if (!celt) return S_OK;
+
+    if (!handle)
+    {
+        handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
+        if (!handle) return S_FALSE;
+        This->data.u.filecoll.find = handle;
+    }
+    else if (!FindNextFileW(handle, &data))
+        return S_FALSE;
+
+    do
+    {
+        if (is_file_data(&data))
+            --celt;
+    } while (celt && FindNextFileW(handle, &data));
+
+    return celt ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+
+    TRACE("(%p)\n", This);
+
+    FindClose(This->data.u.filecoll.find);
+    This->data.u.filecoll.find = NULL;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    TRACE("(%p)->(%p)\n", This, pclone);
+    return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
+}
+
+static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
+    enumvariant_QueryInterface,
+    enumvariant_AddRef,
+    filecoll_enumvariant_Release,
+    filecoll_enumvariant_Next,
+    filecoll_enumvariant_Skip,
+    filecoll_enumvariant_Reset,
+    filecoll_enumvariant_Clone
+};
+
+static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
+{
+    struct enumvariant *This;
+
+    *newenum = NULL;
+
+    This = heap_alloc(sizeof(*This));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
+    This->ref = 1;
+    This->data.u.filecoll.find = NULL;
+    This->data.u.filecoll.coll = collection;
+    IFileCollection_AddRef(&collection->IFileCollection_iface);
+
+    *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
+
+    return S_OK;
+}
+
+static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p)->(%d)\n", This, ref);
+
+    if (!ref)
+    {
+        IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT find_next_drive(struct enumvariant *penum)
+{
+    int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
+
+    for (; i < 32; i++)
+        if (penum->data.u.drivecoll.coll->drives & (1 << i))
+        {
+            penum->data.u.drivecoll.cur = i;
+            return S_OK;
+        }
+
+    return S_FALSE;
+}
+
+static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    ULONG count = 0;
+
+    TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
+
+    if (fetched)
+        *fetched = 0;
+
+    if (!celt) return S_OK;
+
+    while (find_next_drive(This) == S_OK)
+    {
+        IDrive *drive;
+        HRESULT hr;
+
+        hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
+        if (FAILED(hr)) return hr;
+
+        V_VT(&var[count]) = VT_DISPATCH;
+        V_DISPATCH(&var[count]) = (IDispatch*)drive;
+
+        if (++count >= celt) break;
+    }
+
+    if (fetched)
+        *fetched = count;
+
+    return (count < celt) ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+
+    TRACE("(%p)->(%d)\n", This, celt);
+
+    if (!celt) return S_OK;
+
+    while (celt && find_next_drive(This) == S_OK)
+        celt--;
+
+    return celt ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+
+    TRACE("(%p)\n", This);
+
+    This->data.u.drivecoll.cur = -1;
+    return S_OK;
+}
+
+static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
+{
+    struct enumvariant *This = impl_from_IEnumVARIANT(iface);
+    FIXME("(%p)->(%p): stub\n", This, pclone);
+    return E_NOTIMPL;
+}
+
+static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
+    enumvariant_QueryInterface,
+    enumvariant_AddRef,
+    drivecoll_enumvariant_Release,
+    drivecoll_enumvariant_Next,
+    drivecoll_enumvariant_Skip,
+    drivecoll_enumvariant_Reset,
+    drivecoll_enumvariant_Clone
+};
+
+static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
+{
+    struct enumvariant *This;
+
+    *newenum = NULL;
+
+    This = heap_alloc(sizeof(*This));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
+    This->ref = 1;
+    This->data.u.drivecoll.coll = collection;
+    This->data.u.drivecoll.cur = -1;
+    IDriveCollection_AddRef(&collection->IDriveCollection_iface);
+
+    *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+
+    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
+
+    *obj = NULL;
+
+    if (IsEqualIID( riid, &IID_IFolderCollection ) ||
+        IsEqualIID( riid, &IID_IDispatch ) ||
+        IsEqualIID( riid, &IID_IUnknown ))
+    {
+        *obj = iface;
+        IFolderCollection_AddRef(iface);
+    }
+    else
+        return E_NOINTERFACE;
+
+    return S_OK;
+}
+
+static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p)->(%d)\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+    TRACE("(%p)->(%d)\n", This, ref);
+
+    if (!ref)
+    {
+        SysFreeString(This->path);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    TRACE("(%p)->(%p)\n", This, pctinfo);
+    *pctinfo = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
+                                        LCID lcid, ITypeInfo **ppTInfo)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
+    return get_typeinfo(IFolderCollection_tid, ppTInfo);
+}
+
+static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
+                                        LPOLESTR *rgszNames, UINT cNames,
+                                        LCID lcid, DISPID *rgDispId)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+    hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
+    if(SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
+                                      REFIID riid, LCID lcid, WORD wFlags,
+                                      DISPPARAMS *pDispParams, VARIANT *pVarResult,
+                                      EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    ITypeInfo *typeinfo;
+    HRESULT hr;
+
+    TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
+           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
+    if(SUCCEEDED(hr))
+    {
+        hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
+                pDispParams, pVarResult, pExcepInfo, puArgErr);
+        ITypeInfo_Release(typeinfo);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    FIXME("(%p)->(%p): stub\n", This, folder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+
+    TRACE("(%p)->(%p)\n", This, newenum);
+
+    if(!newenum)
+        return E_POINTER;
+
+    return create_foldercoll_enum(This, newenum);
+}
+
+static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
+{
+    struct foldercollection *This = impl_from_IFolderCollection(iface);
+    static const WCHAR allW[] = {'\\','*',0};
+    WIN32_FIND_DATAW data;
+    WCHAR pathW[MAX_PATH];
+    HANDLE handle;
+
+    TRACE("(%p)->(%p)\n", This, count);
+
+    if(!count)
+        return E_POINTER;
+
+    *count = 0;
+
+    strcpyW(pathW, This->path);
+    strcatW(pathW, allW);
+    handle = FindFirstFileW(pathW, &data);
+    if (handle == INVALID_HANDLE_VALUE)
+        return HRESULT_FROM_WIN32(GetLastError());
+
+    do
+    {
+        if (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;
+    }
+
+    *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 = iface;
+        IFileCollection_AddRef(iface);
+    }
+    else
+        return E_NOINTERFACE;
+
+    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);
+    FIXME("(%p)->(%p)\n", This, count);
+    return E_NOTIMPL;
+}
+
+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;
+    }
 
-static int textstream_check_iomode(struct textstream *This, enum iotype type)
-{
-    if (type == IORead)
-        return This->mode == ForWriting || This->mode == ForAppending;
-    else
-        return 1;
+    *files = &This->IFileCollection_iface;
+    return S_OK;
 }
 
-static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
+static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
+    struct drivecollection *This = impl_from_IDriveCollection(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 = NULL;
+
+    if (IsEqualIID( riid, &IID_IDriveCollection ) ||
+        IsEqualIID( riid, &IID_IDispatch ) ||
+        IsEqualIID( riid, &IID_IUnknown ))
     {
         *obj = iface;
-        ITextStream_AddRef(iface);
-        return S_OK;
+        IDriveCollection_AddRef(iface);
     }
+    else
+        return E_NOINTERFACE;
 
-    *obj = NULL;
-    return E_NOINTERFACE;
+    return S_OK;
 }
 
-static ULONG WINAPI textstream_AddRef(ITextStream *iface)
+static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
+    struct drivecollection *This = impl_from_IDriveCollection(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
     TRACE("(%p)->(%d)\n", This, ref);
     return ref;
 }
 
-static ULONG WINAPI textstream_Release(ITextStream *iface)
+static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
+    struct drivecollection *This = impl_from_IDriveCollection(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
     TRACE("(%p)->(%d)\n", This, ref);
 
@@ -123,33 +1898,33 @@ static ULONG WINAPI textstream_Release(ITextStream *iface)
     return ref;
 }
 
-static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
+static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
+    struct drivecollection *This = impl_from_IDriveCollection(iface);
     TRACE("(%p)->(%p)\n", This, pctinfo);
     *pctinfo = 1;
     return S_OK;
 }
 
-static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
+static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
                                         LCID lcid, ITypeInfo **ppTInfo)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
+    struct drivecollection *This = impl_from_IDriveCollection(iface);
     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
-    return get_typeinfo(ITextStream_tid, ppTInfo);
+    return get_typeinfo(IDriveCollection_tid, ppTInfo);
 }
 
-static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
+static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
                                         LPOLESTR *rgszNames, UINT cNames,
                                         LCID lcid, DISPID *rgDispId)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
+    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(ITextStream_tid, &typeinfo);
+    hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
     if(SUCCEEDED(hr))
     {
         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
@@ -159,19 +1934,19 @@ static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
     return hr;
 }
 
-static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
+static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
                                       REFIID riid, LCID lcid, WORD wFlags,
                                       DISPPARAMS *pDispParams, VARIANT *pVarResult,
                                       EXCEPINFO *pExcepInfo, UINT *puArgErr)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
+    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(ITextStream_tid, &typeinfo);
+    hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
     if(SUCCEEDED(hr))
     {
         hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
@@ -182,144 +1957,68 @@ static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
     return hr;
 }
 
-static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%p): stub\n", This, line);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%p): stub\n", This, column);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%p): stub\n", This, eos);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%p): stub\n", This, eol);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%p): stub\n", This, text);
-
-    if (textstream_check_iomode(This, IORead))
-        return CTL_E_BADFILEMODE;
-
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
+static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%p): stub\n", This, text);
-
-    if (textstream_check_iomode(This, IORead))
-        return CTL_E_BADFILEMODE;
-
+    struct drivecollection *This = impl_from_IDriveCollection(iface);
+    FIXME("(%p)->(%p): stub\n", This, drive);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
+static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%p): stub\n", This, text);
-
-    if (textstream_check_iomode(This, IORead))
-        return CTL_E_BADFILEMODE;
+    struct drivecollection *This = impl_from_IDriveCollection(iface);
 
-    return E_NOTIMPL;
-}
+    TRACE("(%p)->(%p)\n", This, ppenum);
 
-static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
-    return E_NOTIMPL;
-}
+    if(!ppenum)
+        return E_POINTER;
 
-static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
-    return E_NOTIMPL;
+    return create_drivecoll_enum(This, ppenum);
 }
 
-static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
+static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
 {
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p)->(%d): stub\n", This, lines);
-    return E_NOTIMPL;
-}
+    struct drivecollection *This = impl_from_IDriveCollection(iface);
 
-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;
-}
+    TRACE("(%p)->(%p)\n", This, count);
 
-static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p): stub\n", This);
-    return E_NOTIMPL;
-}
+    if (!count) return E_POINTER;
 
-static HRESULT WINAPI textstream_Close(ITextStream *iface)
-{
-    struct textstream *This = impl_from_ITextStream(iface);
-    FIXME("(%p): stub\n", This);
-    return E_NOTIMPL;
+    *count = This->count;
+    return S_OK;
 }
 
-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 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_textstream(IOMode mode, ITextStream **ret)
+static HRESULT create_drivecoll(IDriveCollection **drives)
 {
-    struct textstream *stream;
+    struct drivecollection *This;
+    DWORD mask;
 
-    stream = heap_alloc(sizeof(struct textstream));
-    if (!stream) return E_OUTOFMEMORY;
+    *drives = NULL;
 
-    stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
-    stream->ref = 1;
-    stream->mode = mode;
+    This = heap_alloc(sizeof(*This));
+    if (!This) return E_OUTOFMEMORY;
 
-    *ret = &stream->ITextStream_iface;
+    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;
+
+    *drives = &This->IDriveCollection_iface;
     return S_OK;
 }
 
@@ -331,8 +2030,9 @@ static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **
 
     *obj = NULL;
 
-    if (IsEqualGUID( riid, &IID_IFolder ) ||
-        IsEqualGUID( riid, &IID_IUnknown))
+    if (IsEqualIID( riid, &IID_IFolder ) ||
+        IsEqualIID( riid, &IID_IDispatch ) ||
+        IsEqualIID( riid, &IID_IUnknown))
     {
         *obj = iface;
         IFolder_AddRef(iface);
@@ -358,7 +2058,10 @@ static ULONG WINAPI folder_Release(IFolder *iface)
     TRACE("(%p)->(%d)\n", This, ref);
 
     if (!ref)
+    {
+        SysFreeString(This->path);
         heap_free(This);
+    }
 
     return ref;
 }
@@ -425,15 +2128,39 @@ static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
 {
     struct folder *This = impl_from_IFolder(iface);
-    FIXME("(%p)->(%p): stub\n", This, path);
-    return E_NOTIMPL;
+
+    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);
-    FIXME("(%p)->(%p): stub\n", This, name);
-    return E_NOTIMPL;
+    WCHAR *ptr;
+
+    TRACE("(%p)->(%p)\n", This, name);
+
+    if(!name)
+        return E_POINTER;
+
+    *name = NULL;
+
+    ptr = strrchrW(This->path, '\\');
+    if (ptr)
+    {
+        *name = SysAllocString(ptr+1);
+        TRACE("%s\n", debugstr_w(*name));
+        if (!*name) return E_OUTOFMEMORY;
+    }
+    else
+        return E_FAIL;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
@@ -551,15 +2278,25 @@ static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
 {
     struct folder *This = impl_from_IFolder(iface);
-    FIXME("(%p)->(%p): stub\n", This, folders);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%p)\n", This, folders);
+
+    if(!folders)
+        return E_POINTER;
+
+    return create_foldercoll(This->path, folders);
 }
 
 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
 {
     struct folder *This = impl_from_IFolder(iface);
-    FIXME("(%p)->(%p): stub\n", This, files);
-    return E_NOTIMPL;
+
+    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,
@@ -601,15 +2338,25 @@ static const IFolderVtbl foldervtbl = {
     folder_CreateTextFile
 };
 
-static HRESULT create_folder(IFolder **folder)
+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;
+    }
 
     *folder = &This->IFolder_iface;
 
@@ -653,7 +2400,10 @@ static ULONG WINAPI file_Release(IFile *iface)
     TRACE("(%p) ref=%d\n", This, ref);
 
     if(!ref)
+    {
         heap_free(This->path);
+        heap_free(This);
+    }
 
     return ref;
 }
@@ -722,11 +2472,29 @@ static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *pbstrPath)
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *pbstrName)
+static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
 {
     struct file *This = impl_from_IFile(iface);
-    FIXME("(%p)->(%p)\n", This, pbstrName);
-    return E_NOTIMPL;
+    WCHAR *ptr;
+
+    TRACE("(%p)->(%p)\n", This, name);
+
+    if(!name)
+        return E_POINTER;
+
+    *name = NULL;
+
+    ptr = strrchrW(This->path, '\\');
+    if (ptr)
+    {
+        *name = SysAllocString(ptr+1);
+        TRACE("%s\n", debugstr_w(*name));
+        if (!*name) return E_OUTOFMEMORY;
+    }
+    else
+        return E_FAIL;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
@@ -866,11 +2634,18 @@ static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode IOMode, Tristate Format, ITextStream **ppts)
+static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
 {
     struct file *This = impl_from_IFile(iface);
-    FIXME("(%p)->(%x %x %p)\n", This, IOMode, Format, ppts);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
+
+    if (format == TristateUseDefault) {
+        FIXME("default format not handled, defaulting to unicode\n");
+        format = TristateTrue;
+    }
+
+    return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
 }
 
 static const IFileVtbl file_vtbl = {
@@ -1054,17 +2829,66 @@ static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
 
 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
 {
-    FIXME("%p %p\n", iface, ppdrives);
-
-    return E_NOTIMPL;
+    TRACE("%p %p\n", iface, ppdrives);
+    return create_drivecoll(ppdrives);
 }
 
 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
-                                            BSTR Name, BSTR *pbstrResult)
+                                            BSTR Name, BSTR *Result)
 {
-    FIXME("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), pbstrResult);
+    BSTR ret;
 
-    return E_NOTIMPL;
+    TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
+
+    if (!Result) return E_POINTER;
+
+    if (Path && Name)
+    {
+        int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
+
+        /* if both parts have backslashes strip one from Path */
+        if (Path[path_len-1] == '\\' && Name[0] == '\\')
+        {
+            path_len -= 1;
+
+            ret = SysAllocStringLen(NULL, path_len + name_len);
+            if (ret)
+            {
+                strcpyW(ret, Path);
+                ret[path_len] = 0;
+                strcatW(ret, Name);
+            }
+        }
+        else if (Path[path_len-1] != '\\' && Name[0] != '\\')
+        {
+            ret = SysAllocStringLen(NULL, path_len + name_len + 1);
+            if (ret)
+            {
+                strcpyW(ret, Path);
+                if (Path[path_len-1] != ':')
+                    strcatW(ret, bsW);
+                strcatW(ret, Name);
+            }
+        }
+        else
+        {
+            ret = SysAllocStringLen(NULL, path_len + name_len);
+            if (ret)
+            {
+                strcpyW(ret, Path);
+                strcatW(ret, Name);
+            }
+        }
+    }
+    else if (Path || Name)
+        ret = SysAllocString(Path ? Path : Name);
+    else
+        ret = SysAllocStringLen(NULL, 0);
+
+    if (!ret) return E_OUTOFMEMORY;
+    *Result = ret;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR Path,
@@ -1334,11 +3158,24 @@ static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
 }
 
 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
-                                            IFolder **ppfolder)
+                                            IFolder **folder)
 {
-    FIXME("%p %s %p\n", iface, debugstr_w(FolderPath), ppfolder);
+    DWORD attrs;
 
-    return E_NOTIMPL;
+    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,
@@ -1530,8 +3367,10 @@ static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
         return CTL_E_FILENOTFOUND;
 
     src_len = get_parent_folder_name(source, source_len);
-    if(src_len+1 >= MAX_PATH)
+    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++] = '\\';
@@ -1674,10 +3513,9 @@ static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *d
                     FindClose(f);
                     return CTL_E_FILEALREADYEXISTS;
                 }
-            }else {
-                FindClose(f);
-                return create_error(GetLastError());
             }
+
+            FindClose(f);
             return create_error(GetLastError());
         }
         copied = TRUE;
@@ -1726,24 +3564,36 @@ static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
         return HRESULT_FROM_WIN32(GetLastError());
     }
 
-    return create_folder(folder);
+    return create_folder(path, folder);
 }
 
-static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR FileName,
-                                            VARIANT_BOOL Overwrite, VARIANT_BOOL Unicode,
-                                            ITextStream **ppts)
+static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
+                                            VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
+                                            ITextStream **stream)
 {
-    FIXME("%p %s %d %d %p\n", iface, debugstr_w(FileName), Overwrite, Unicode, ppts);
+    DWORD disposition;
 
-    return E_NOTIMPL;
+    TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
+
+    disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
+    return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
 }
 
 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
                                             IOMode mode, VARIANT_BOOL create,
                                             Tristate format, ITextStream **stream)
 {
-    FIXME("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
-    return create_textstream(mode, stream);
+    DWORD disposition;
+
+    TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
+    disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
+
+    if (format == TristateUseDefault) {
+        FIXME("default format not handled, defaulting to unicode\n");
+        format = TristateTrue;
+    }
+
+    return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
 }
 
 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
@@ -1758,7 +3608,7 @@ static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
 
 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
 {
-    static WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
+    static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
     DWORDLONG version;
     WORD a, b, c, d;
 
index 23b3975..3891ac8 100644 (file)
@@ -90,9 +90,14 @@ static ITypeInfo *typeinfos[LAST_tid];
 static REFIID tid_ids[] = {
     &IID_NULL,
     &IID_IDictionary,
+    &IID_IDrive,
+    &IID_IDriveCollection,
+    &IID_IFile,
+    &IID_IFileCollection,
     &IID_IFileSystem3,
     &IID_IFolder,
-    &IID_IFile
+    &IID_IFolderCollection,
+    &IID_ITextStream
 };
 
 static HRESULT load_typelib(void)
index 4b18af1..53125ee 100644 (file)
@@ -15,6 +15,9 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
+
+#pragma makedep regtypelib
+
 import "unknwn.idl";
 import "objidl.idl";
 import "oaidl.idl";
@@ -24,6 +27,7 @@ cpp_quote("#undef CopyFile")
 cpp_quote("#undef DeleteFile")
 cpp_quote("#undef MoveFile")
 cpp_quote("#endif")
+cpp_quote("#define CTL_E_ENDOFFILE STD_CTL_SCODE(62)") /* this is not defined in public headers */
 
 [
   uuid(420B2830-E718-11CF-893D-00A0C9054228),
@@ -33,23 +37,13 @@ library Scripting
 {
     importlib("stdole2.tlb");
 
-    interface IDictionary;
-    interface IDrive;
-    interface IDriveCollection;
-    interface IFile;
-    interface IFileCollection;
-    interface IFileSystem;
-    interface IFileSystem3;
     interface IFolder;
-    interface IFolderCollection;
-    interface IScriptEncoder;
-    interface ITextStream;
 
     typedef enum CompareMethod
     {
-        BinaryCompare   = 0,
-        TextCompare     = 1,
-        DatabaseCompare = 2
+        BinaryCompare,
+        TextCompare,
+        DatabaseCompare
     } CompareMethod;
 
     typedef enum IOMode
@@ -61,10 +55,10 @@ library Scripting
 
     typedef enum Tristate
     {
-        TristateTrue       = 0xffffffff,
-        TristateFalse      = 0,
-        TristateUseDefault = 0xfffffffe,
-        TristateMixed      = 0xfffffffe
+        TristateTrue       = -1,
+        TristateFalse      =  0,
+        TristateUseDefault = -2,
+        TristateMixed      = -2
     } Tristate;
 
     typedef enum FileAttribute
@@ -82,26 +76,26 @@ library Scripting
 
     typedef enum SpecialFolderConst
     {
-        WindowsFolder = 0,
-        SystemFolder = 1,
-        TemporaryFolder = 2
+        WindowsFolder,
+        SystemFolder,
+        TemporaryFolder
     } SpecialFolderConst;
 
     typedef enum DriveTypeConst
     {
-        UnknownType = 0,
-        Removable = 1,
-        Fixed = 2,
-        Remote = 3,
-        CDRom = 4,
-        RamDisk = 5
+        UnknownType,
+        Removable,
+        Fixed,
+        Remote,
+        CDRom,
+        RamDisk
     } DriveTypeConst;
 
     typedef enum StandardStreamTypes
     {
-        StdIn  = 0,
-        StdOut = 1,
-        StdErr = 2
+        StdIn,
+        StdOut,
+        StdErr
     } StandardStreamTypes;
 
     [
@@ -113,13 +107,13 @@ library Scripting
     ]
     interface IDictionary : IDispatch
     {
-        [id(00000000), propputref]
+        [id(DISPID_VALUE), propputref]
         HRESULT Item([in] VARIANT* Key, [in] VARIANT* pRetItem);
 
-        [id(00000000), propput]
+        [id(DISPID_VALUE), propput]
         HRESULT Item([in] VARIANT* Key, [in] VARIANT* pRetItem);
 
-        [id(00000000), propget]
+        [id(DISPID_VALUE), propget]
         HRESULT Item([in] VARIANT* Key, [out, retval] VARIANT* pRetItem);
 
         [id(0x00000001)]
@@ -161,94 +155,52 @@ library Scripting
 
     [
       odl,
-      uuid(0AB5A3D0-E5B6-11D0-ABF5-00A0C90FFFC0),
+      uuid(C7C3F5A0-88A3-11D0-ABCB-00A0C90FFFC0),
       hidden,
       dual,
       nonextensible,
       oleautomation
     ]
-    interface IFileSystem : IDispatch
+    interface IDrive : IDispatch
     {
-        [id(0x0000271a), propget]
-        HRESULT Drives([out, retval] IDriveCollection** ppdrives);
-
-        [id(0x00002710)]
-        HRESULT BuildPath([in] BSTR Path, [in] BSTR Name, [out, retval] BSTR* pbstrResult);
-
-        [id(0x00002714)]
-        HRESULT GetDriveName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
-
-        [id(0x00002715)]
-        HRESULT GetParentFolderName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
-
-        [id(0x00002716)]
-        HRESULT GetFileName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
-
-        [id(0x00002717)]
-        HRESULT GetBaseName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
-
-        [id(0x00002718)]
-        HRESULT GetExtensionName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
-
-        [id(0x00002712)]
-        HRESULT GetAbsolutePathName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
-
-        [id(0x00002713)]
-        HRESULT GetTempName([out, retval] BSTR* pbstrResult);
-
-        [id(0x0000271f)]
-        HRESULT DriveExists([in] BSTR DriveSpec, [out, retval] VARIANT_BOOL* pfExists);
-
-        [id(0x00002720)]
-        HRESULT FileExists([in] BSTR FileSpec, [out, retval] VARIANT_BOOL* pfExists);
-
-        [id(0x00002721)]
-        HRESULT FolderExists([in] BSTR FolderSpec, [out, retval] VARIANT_BOOL* pfExists);
-
-        [id(0x0000271b)]
-        HRESULT GetDrive([in] BSTR DriveSpec, [out, retval] IDrive** ppdrive);
+        [id(DISPID_VALUE), propget]
+        HRESULT Path([out, retval] BSTR* pbstrPath);
 
-        [id(0x0000271c)]
-        HRESULT GetFile([in] BSTR FilePath, [out, retval] IFile** ppfile);
+        [id(0x00002710), propget]
+        HRESULT DriveLetter([out, retval] BSTR* pbstrLetter);
 
-        [id(0x0000271d)]
-        HRESULT GetFolder([in] BSTR FolderPath, [out, retval] IFolder** ppfolder);
+        [id(0x00002711), propget]
+        HRESULT ShareName([out, retval] BSTR* pbstrShareName);
 
-        [id(0x0000271e)]
-        HRESULT GetSpecialFolder([in] SpecialFolderConst SpecialFolder, [out, retval] IFolder** ppfolder);
+        [id(0x00002712), propget]
+        HRESULT DriveType([out, retval] DriveTypeConst* pdt);
 
-        [id(0x000004b0)]
-        HRESULT DeleteFile([in] BSTR FileSpec, [in, optional, defaultvalue(0)] VARIANT_BOOL Force);
+        [id(0x00002713), propget]
+        HRESULT RootFolder([out, retval] IFolder** ppfolder);
 
-        [id(0x000004b1)]
-        HRESULT DeleteFolder([in] BSTR FolderSpec, [in, optional, defaultvalue(0)] VARIANT_BOOL Force);
+        [id(0x00002715), propget]
+        HRESULT AvailableSpace([out, retval] VARIANT* pvarAvail);
 
-        [id(0x000004b4), helpstring("Move a file"), helpcontext(0x00214bab)]
-        HRESULT MoveFile([in] BSTR Source, [in] BSTR Destination);
+        [id(0x00002714), propget]
+        HRESULT FreeSpace([out, retval] VARIANT* pvarFree);
 
-        [id(0x000004b5)]
-        HRESULT MoveFolder([in] BSTR Source, [in] BSTR Destination);
+        [id(0x00002716), propget]
+        HRESULT TotalSize([out, retval] VARIANT* pvarTotal);
 
-        [id(0x000004b2)]
-        HRESULT CopyFile([in] BSTR Source, [in] BSTR Destination,
-                         [in, optional, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
+        [id(0x00002717), propget]
+        HRESULT VolumeName([out, retval] BSTR* pbstrName);
 
-        [id(0x000004b3)]
-        HRESULT CopyFolder([in] BSTR Source, [in] BSTR Destination,
-                           [in, optional, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
+        [id(0x00002717), propput]
+        HRESULT VolumeName([in] BSTR pbstrName);
 
-        [id(0x00000460)]
-        HRESULT CreateFolder([in] BSTR Path, [out, retval] IFolder** ppfolder);
+        [id(0x00002718), propget]
+        HRESULT FileSystem([out, retval] BSTR* pbstrFileSystem);
 
-        [id(0x0000044d)]
-        HRESULT CreateTextFile([in] BSTR FileName, [in, optional, defaultvalue(-1)] VARIANT_BOOL Overwrite,
-                        [in, optional, defaultvalue(0)] VARIANT_BOOL Unicode, [out, retval] ITextStream** ppts);
+        [id(0x00002719), propget]
+        HRESULT SerialNumber([out, retval] long* pulSerialNumber);
 
-        [id(0x0000044c)]
-        HRESULT OpenTextFile([in] BSTR FileName, [in, optional, defaultvalue(1)] IOMode IOMode,
-                        [in, optional, defaultvalue(0)] VARIANT_BOOL Create,
-                        [in, optional, defaultvalue(0)] Tristate Format,
-                        [out, retval] ITextStream** ppts);
+        [id(0x0000271a), propget]
+        HRESULT IsReady([out, retval] VARIANT_BOOL* pfReady);
     }
 
     [
@@ -260,7 +212,7 @@ library Scripting
       oleautomation
     ]
     interface IDriveCollection : IDispatch {
-        [id(00000000)]
+        [id(DISPID_VALUE), propget]
         HRESULT Item([in] VARIANT Key, [out, retval] IDrive** ppdrive);
 
         [id(DISPID_NEWENUM), propget, restricted, hidden]
@@ -272,65 +224,65 @@ library Scripting
 
     [
       odl,
-      uuid(C7C3F5A0-88A3-11D0-ABCB-00A0C90FFFC0),
+      uuid(53BAD8C1-E718-11CF-893D-00A0C9054228),
       hidden,
       dual,
       nonextensible,
       oleautomation
     ]
-    interface IDrive : IDispatch
+    interface ITextStream : IDispatch
     {
-        [id(00000000), propget]
-        HRESULT Path([out, retval] BSTR* pbstrPath);
-
         [id(0x00002710), propget]
-        HRESULT DriveLetter([out, retval] BSTR* pbstrLetter)
-;
-        [id(0x00002711), propget]
-        HRESULT ShareName([out, retval] BSTR* pbstrShareName);
+        HRESULT Line([out, retval] long* Line);
+
+        [id(0xfffffdef), propget]
+        HRESULT Column([out, retval] long* Column);
 
         [id(0x00002712), propget]
-        HRESULT DriveType([out, retval] DriveTypeConst* pdt);
+        HRESULT AtEndOfStream([out, retval] VARIANT_BOOL* EOS);
 
         [id(0x00002713), propget]
-        HRESULT RootFolder([out, retval] IFolder** ppfolder);
+        HRESULT AtEndOfLine([out, retval] VARIANT_BOOL* EOL);
 
-        [id(0x00002715), propget]
-        HRESULT AvailableSpace([out, retval] VARIANT* pvarAvail);
+        [id(0x00002714)]
+        HRESULT Read([in] long Characters, [out, retval] BSTR* Text);
 
-        [id(0x00002714), propget]
-        HRESULT FreeSpace([out, retval] VARIANT* pvarFree);
+        [id(0x00002715)]
+        HRESULT ReadLine([out, retval] BSTR* Text);
 
-        [id(0x00002716), propget]
-        HRESULT TotalSize([out, retval] VARIANT* pvarTotal);
+        [id(0x00002716)]
+        HRESULT ReadAll([out, retval] BSTR* Text);
 
-        [id(0x00002717), propget]
-        HRESULT VolumeName([out, retval] BSTR* pbstrName);
+        [id(0x00002717)]
+        HRESULT Write([in] BSTR Text);
 
-        [id(0x00002717), propput]
-        HRESULT VolumeName([in] BSTR pbstrName);
+        [id(0x00002718)]
+        HRESULT WriteLine([in, defaultvalue("")] BSTR Text);
 
-        [id(0x00002718), propget]
-        HRESULT FileSystem([out, retval] BSTR* pbstrFileSystem);
+        [id(0x00002719)]
+        HRESULT WriteBlankLines([in] long Lines);
 
-        [id(0x00002719), propget]
-        HRESULT SerialNumber([out, retval] long* pulSerialNumber);
+        [id(0x0000271a)]
+        HRESULT Skip([in] long Characters);
 
-        [id(0x0000271a), propget]
-        HRESULT IsReady([out, retval] VARIANT_BOOL* pfReady);
+        [id(0x0000271b)]
+        HRESULT SkipLine();
+
+        [id(0x0000271c)]
+        HRESULT Close();
     }
 
     [
       odl,
-      uuid(C7C3F5A2-88A3-11D0-ABCB-00A0C90FFFC0),
+      uuid(C7C3F5A4-88A3-11D0-ABCB-00A0C90FFFC0),
       hidden,
       dual,
       nonextensible,
       oleautomation
     ]
-    interface IFolder : IDispatch
+    interface IFile : IDispatch
     {
-        [id(00000000), propget]
+        [id(DISPID_VALUE), propget]
         HRESULT Path([out, retval] BSTR* pbstrPath);
 
         [id(0x000003e8), propget]
@@ -366,50 +318,130 @@ library Scripting
         [id(0x000003f0), propget]
         HRESULT DateLastAccessed([out, retval] DATE* pdate);
 
+        [id(0x000003f1), propget]
+        HRESULT Size([out, retval] VARIANT* pvarSize);
+
         [id(0x000003f2), propget]
         HRESULT Type([out, retval] BSTR* pbstrType);
 
-        [id(0x000004b1)]
-        HRESULT Delete([in, optional, defaultvalue(0)] VARIANT_BOOL Force);
+        [id(0x000004b0)]
+        HRESULT Delete([in, defaultvalue(0)] VARIANT_BOOL Force);
 
-        [id(0x000004b3)]
-        HRESULT Copy([in] BSTR Destination, [in, optional, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
+        [id(0x000004b2)]
+        HRESULT Copy([in] BSTR Destination, [in, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
 
-        [id(0x000004b5)]
+        [id(0x000004b4)]
         HRESULT Move([in] BSTR Destination);
 
-        [id(0x00002710), propget]
-        HRESULT IsRootFolder([out, retval] VARIANT_BOOL* pfRootFolder);
+        [id(0x0000044c)]
+        HRESULT OpenAsTextStream([in, defaultvalue(1)] IOMode IOMode,
+                        [in, defaultvalue(0)] Tristate Format, [out, retval] ITextStream** ppts);
+    }
 
-        [id(0x000003f1), propget]
-        HRESULT Size([out, retval] VARIANT* pvarSize);
+    [
+      odl,
+      uuid(0AB5A3D0-E5B6-11D0-ABF5-00A0C90FFFC0),
+      hidden,
+      dual,
+      nonextensible,
+      oleautomation
+    ]
+    interface IFileSystem : IDispatch
+    {
+        [id(0x0000271a), propget]
+        HRESULT Drives([out, retval] IDriveCollection** ppdrives);
 
-        [id(0x00002711), propget]
-        HRESULT SubFolders([out, retval] IFolderCollection** ppfolders);
+        [id(0x00002710)]
+        HRESULT BuildPath([in] BSTR Path, [in] BSTR Name, [out, retval] BSTR* pbstrResult);
 
-        [id(0x00002712), propget]
-        HRESULT Files([out, retval] IFileCollection** ppfiles);
+        [id(0x00002714)]
+        HRESULT GetDriveName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
+
+        [id(0x00002715)]
+        HRESULT GetParentFolderName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
+
+        [id(0x00002716)]
+        HRESULT GetFileName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
+
+        [id(0x00002717)]
+        HRESULT GetBaseName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
+
+        [id(0x00002718)]
+        HRESULT GetExtensionName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
+
+        [id(0x00002712)]
+        HRESULT GetAbsolutePathName([in] BSTR Path, [out, retval] BSTR* pbstrResult);
+
+        [id(0x00002713)]
+        HRESULT GetTempName([out, retval] BSTR* pbstrResult);
+
+        [id(0x0000271f)]
+        HRESULT DriveExists([in] BSTR DriveSpec, [out, retval] VARIANT_BOOL* pfExists);
+
+        [id(0x00002720)]
+        HRESULT FileExists([in] BSTR FileSpec, [out, retval] VARIANT_BOOL* pfExists);
+
+        [id(0x00002721)]
+        HRESULT FolderExists([in] BSTR FolderSpec, [out, retval] VARIANT_BOOL* pfExists);
+
+        [id(0x0000271b)]
+        HRESULT GetDrive([in] BSTR DriveSpec, [out, retval] IDrive** ppdrive);
+
+        [id(0x0000271c)]
+        HRESULT GetFile([in] BSTR FilePath, [out, retval] IFile** ppfile);
+
+        [id(0x0000271d)]
+        HRESULT GetFolder([in] BSTR FolderPath, [out, retval] IFolder** ppfolder);
+
+        [id(0x0000271e)]
+        HRESULT GetSpecialFolder([in] SpecialFolderConst SpecialFolder, [out, retval] IFolder** ppfolder);
+
+        [id(0x000004b0)]
+        HRESULT DeleteFile([in] BSTR FileSpec, [in, defaultvalue(0)] VARIANT_BOOL Force);
+
+        [id(0x000004b1)]
+        HRESULT DeleteFolder([in] BSTR FolderSpec, [in, defaultvalue(0)] VARIANT_BOOL Force);
+
+        [id(0x000004b4), helpstring("Move a file"), helpcontext(0x00214bab)]
+        HRESULT MoveFile([in] BSTR Source, [in] BSTR Destination);
+
+        [id(0x000004b5)]
+        HRESULT MoveFolder([in] BSTR Source, [in] BSTR Destination);
+
+        [id(0x000004b2)]
+        HRESULT CopyFile([in] BSTR Source, [in] BSTR Destination,
+                         [in, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
+
+        [id(0x000004b3)]
+        HRESULT CopyFolder([in] BSTR Source, [in] BSTR Destination,
+                           [in, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
+
+        [id(0x00000460)]
+        HRESULT CreateFolder([in] BSTR Path, [out, retval] IFolder** ppfolder);
 
         [id(0x0000044d)]
-        HRESULT CreateTextFile([in] BSTR FileName, [in, optional, defaultvalue(-1)] VARIANT_BOOL Overwrite,
-                        [in, optional, defaultvalue(0)] VARIANT_BOOL Unicode, [out, retval] ITextStream** ppts);
+        HRESULT CreateTextFile([in] BSTR FileName, [in, defaultvalue(-1)] VARIANT_BOOL Overwrite,
+                        [in, defaultvalue(0)] VARIANT_BOOL Unicode, [out, retval] ITextStream** ppts);
+
+        [id(0x0000044c)]
+        HRESULT OpenTextFile([in] BSTR FileName, [in, defaultvalue(1)] IOMode IOMode,
+                        [in, defaultvalue(0)] VARIANT_BOOL Create,
+                        [in, defaultvalue(0)] Tristate Format,
+                        [out, retval] ITextStream** ppts);
     }
 
     [
       odl,
-      uuid(C7C3F5A3-88A3-11D0-ABCB-00A0C90FFFC0),
+      uuid(C7C3F5A5-88A3-11D0-ABCB-00A0C90FFFC0),
       hidden,
       dual,
       nonextensible,
       oleautomation
     ]
-    interface IFolderCollection : IDispatch
+    interface IFileCollection : IDispatch
     {
-        [id(0x00000002)]
-        HRESULT Add([in] BSTR Name, [out, retval] IFolder** ppfolder);
-
-        [id(00000000), propget]
-        HRESULT Item([in] VARIANT Key, [out, retval] IFolder** ppfolder);
+        [id(DISPID_VALUE), propget]
+        HRESULT Item([in] VARIANT Key, [out, retval] IFile** ppfile);
 
         [id(DISPID_NEWENUM), propget, restricted, hidden]
         HRESULT _NewEnum([out, retval] IUnknown** ppenum);
@@ -420,16 +452,19 @@ library Scripting
 
     [
       odl,
-      uuid(C7C3F5A5-88A3-11D0-ABCB-00A0C90FFFC0),
+      uuid(C7C3F5A3-88A3-11D0-ABCB-00A0C90FFFC0),
       hidden,
       dual,
       nonextensible,
       oleautomation
     ]
-    interface IFileCollection : IDispatch
+    interface IFolderCollection : IDispatch
     {
-        [id(00000000), propget]
-        HRESULT Item([in] VARIANT Key, [out, retval] IFile** ppfile);
+        [id(0x00000002)]
+        HRESULT Add([in] BSTR Name, [out, retval] IFolder** ppfolder);
+
+        [id(DISPID_VALUE), propget]
+        HRESULT Item([in] VARIANT Key, [out, retval] IFolder** ppfolder);
 
         [id(DISPID_NEWENUM), propget, restricted, hidden]
         HRESULT _NewEnum([out, retval] IUnknown** ppenum);
@@ -440,15 +475,15 @@ library Scripting
 
     [
       odl,
-      uuid(C7C3F5A4-88A3-11D0-ABCB-00A0C90FFFC0),
+      uuid(C7C3F5A2-88A3-11D0-ABCB-00A0C90FFFC0),
       hidden,
       dual,
       nonextensible,
       oleautomation
     ]
-    interface IFile : IDispatch
+    interface IFolder : IDispatch
     {
-        [id(00000000), propget]
+        [id(DISPID_VALUE), propget]
         HRESULT Path([out, retval] BSTR* pbstrPath);
 
         [id(0x000003e8), propget]
@@ -484,74 +519,33 @@ library Scripting
         [id(0x000003f0), propget]
         HRESULT DateLastAccessed([out, retval] DATE* pdate);
 
-        [id(0x000003f1), propget]
-        HRESULT Size([out, retval] VARIANT* pvarSize);
-
         [id(0x000003f2), propget]
         HRESULT Type([out, retval] BSTR* pbstrType);
 
-        [id(0x000004b0)]
-        HRESULT Delete([in, optional, defaultvalue(0)] VARIANT_BOOL Force);
+        [id(0x000004b1)]
+        HRESULT Delete([in, defaultvalue(0)] VARIANT_BOOL Force);
 
-        [id(0x000004b2)]
-        HRESULT Copy([in] BSTR Destination, [in, optional, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
+        [id(0x000004b3)]
+        HRESULT Copy([in] BSTR Destination, [in, defaultvalue(-1)] VARIANT_BOOL OverWriteFiles);
 
-        [id(0x000004b4)]
+        [id(0x000004b5)]
         HRESULT Move([in] BSTR Destination);
 
-        [id(0x0000044c)]
-        HRESULT OpenAsTextStream([in, optional, defaultvalue(1)] IOMode IOMode,
-                        [in, optional, defaultvalue(0)] Tristate Format, [out, retval] ITextStream** ppts);
-    }
-
-    [
-      odl,
-      uuid(53BAD8C1-E718-11CF-893D-00A0C9054228),
-      hidden,
-      dual,
-      nonextensible,
-      oleautomation
-    ]
-    interface ITextStream : IDispatch
-    {
         [id(0x00002710), propget]
-        HRESULT Line([out, retval] long* Line);
-
-        [id(0xfffffdef), propget]
-        HRESULT Column([out, retval] long* Column);
-
-        [id(0x00002712), propget]
-        HRESULT AtEndOfStream([out, retval] VARIANT_BOOL* EOS);
-
-        [id(0x00002713), propget]
-        HRESULT AtEndOfLine([out, retval] VARIANT_BOOL* EOL);
-
-        [id(0x00002714)]
-        HRESULT Read([in] long Characters, [out, retval] BSTR* Text);
-
-        [id(0x00002715)]
-        HRESULT ReadLine([out, retval] BSTR* Text);
-
-        [id(0x00002716)]
-        HRESULT ReadAll([out, retval] BSTR* Text);
-
-        [id(0x00002717)]
-        HRESULT Write([in] BSTR Text);
-
-        [id(0x00002718)]
-        HRESULT WriteLine([in, optional, defaultvalue("")] BSTR Text);
+        HRESULT IsRootFolder([out, retval] VARIANT_BOOL* pfRootFolder);
 
-        [id(0x00002719)]
-        HRESULT WriteBlankLines([in] long Lines);
+        [id(0x000003f1), propget]
+        HRESULT Size([out, retval] VARIANT* pvarSize);
 
-        [id(0x0000271a)]
-        HRESULT Skip([in] long Characters);
+        [id(0x00002711), propget]
+        HRESULT SubFolders([out, retval] IFolderCollection** ppfolders);
 
-        [id(0x0000271b)]
-        HRESULT SkipLine();
+        [id(0x00002712), propget]
+        HRESULT Files([out, retval] IFileCollection** ppfiles);
 
-        [id(0x0000271c)]
-        HRESULT Close();
+        [id(0x0000044d)]
+        HRESULT CreateTextFile([in] BSTR FileName, [in, defaultvalue(-1)] VARIANT_BOOL Overwrite,
+                        [in, defaultvalue(0)] VARIANT_BOOL Unicode, [out, retval] ITextStream** ppts);
     }
 
     [
@@ -565,7 +559,7 @@ library Scripting
     {
         [id(0x00004e20)]
         HRESULT GetStandardStream([in] StandardStreamTypes StandardStreamType,
-                        [in, optional, defaultvalue(0)] VARIANT_BOOL Unicode, [out, retval] ITextStream** ppts);
+                        [in, defaultvalue(0)] VARIANT_BOOL Unicode, [out, retval] ITextStream** ppts);
 
         [id(0x00004e2a)]
         HRESULT GetFileVersion([in] BSTR FileName, [out, retval] BSTR* FileVersion);
@@ -579,7 +573,7 @@ library Scripting
     ]
     interface IScriptEncoder : IDispatch
     {
-        [id(00000000)]
+        [id(DISPID_VALUE)]
         HRESULT EncodeScriptFile([in] BSTR szExt, [in] BSTR bstrStreamIn, [in] long cFlags,
                         [in] BSTR bstrDefaultLang, [out, retval] BSTR* pbstrStreamOut);
     }
index 4fccf44..f3ba4aa 100644 (file)
@@ -47,10 +47,14 @@ typedef enum tid_t
 {
     NULL_tid,
     IDictionary_tid,
+    IDrive_tid,
+    IDriveCollection_tid,
+    IFile_tid,
+    IFileCollection_tid,
     IFileSystem3_tid,
     IFolder_tid,
+    IFolderCollection_tid,
     ITextStream_tid,
-    IFile_tid,
     LAST_tid
 } tid_t;
 
index beea921..ba6f9a7 100644 (file)
@@ -19,7 +19,7 @@ HKCR
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
             TypeLib = s '{420B2830-E718-11CF-893D-00A0C9054228}' { val Version = s '1.0' }
         }
-        '{0AB5A3D0-E5B6-11D0-ABF5-00A0C90FFFC0}' = s 'IFileSystem'
+        '{C7C3F5A0-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IDrive'
         {
             ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
@@ -31,19 +31,19 @@ HKCR
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
             TypeLib = s '{420B2830-E718-11CF-893D-00A0C9054228}' { val Version = s '1.0' }
         }
-        '{C7C3F5A0-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IDrive'
+        '{53BAD8C1-E718-11CF-893D-00A0C9054228}' = s 'ITextStream'
         {
             ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
             TypeLib = s '{420B2830-E718-11CF-893D-00A0C9054228}' { val Version = s '1.0' }
         }
-        '{C7C3F5A2-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IFolder'
+        '{C7C3F5A4-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IFile'
         {
             ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
             TypeLib = s '{420B2830-E718-11CF-893D-00A0C9054228}' { val Version = s '1.0' }
         }
-        '{C7C3F5A3-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IFolderCollection'
+        '{0AB5A3D0-E5B6-11D0-ABF5-00A0C90FFFC0}' = s 'IFileSystem'
         {
             ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
@@ -55,13 +55,13 @@ HKCR
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
             TypeLib = s '{420B2830-E718-11CF-893D-00A0C9054228}' { val Version = s '1.0' }
         }
-        '{C7C3F5A4-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IFile'
+        '{C7C3F5A3-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IFolderCollection'
         {
             ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
             TypeLib = s '{420B2830-E718-11CF-893D-00A0C9054228}' { val Version = s '1.0' }
         }
-        '{53BAD8C1-E718-11CF-893D-00A0C9054228}' = s 'ITextStream'
+        '{C7C3F5A2-88A3-11D0-ABCB-00A0C90FFFC0}' = s 'IFolder'
         {
             ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'
             ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'
index 5ba07de..b5916b5 100644 (file)
@@ -171,7 +171,7 @@ reactos/dll/win32/rsabase             # Synced to Wine-1.7.1
 reactos/dll/win32/rsaenh              # Synced to Wine-1.7.17
 reactos/dll/win32/sccbase             # Synced to Wine-1.7.1
 reactos/dll/win32/schannel            # Synced to Wine-1.7.1
-reactos/dll/win32/scrrun              # Synced to Wine-1.7.1
+reactos/dll/win32/scrrun              # Synced to Wine-1.7.17
 reactos/dll/win32/secur32             # Forked
 reactos/dll/win32/security            # Forked (different .spec)
 reactos/dll/win32/sensapi             # Synced to Wine-1.7.1