[PATCH v8 2/3] shell32: Implement FolderItems_Item.

Sebastian Lackner sebastian at fds-team.de
Mon Aug 22 05:16:21 CDT 2016


On 19.08.2016 11:43, Alex Henrie wrote:
> Cc: Sebastian Lackner <sebastian at fds-team.de>
> 
> Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
> ---
>  dlls/shell32/shelldispatch.c       | 133 +++++++++++++++++++++++++++++++++++--
>  dlls/shell32/tests/shelldispatch.c |  12 ----
>  2 files changed, 127 insertions(+), 18 deletions(-)
> 
> diff --git a/dlls/shell32/shelldispatch.c b/dlls/shell32/shelldispatch.c
> index ac79302..a456ad4 100644
> --- a/dlls/shell32/shelldispatch.c
> +++ b/dlls/shell32/shelldispatch.c
> @@ -68,6 +68,9 @@ typedef struct {
>  typedef struct {
>      FolderItems3 FolderItems3_iface;
>      LONG ref;
> +    VARIANT dir;
> +    BSTR *item_paths;
> +    LONG item_count;
>  } FolderItemsImpl;
>  
>  typedef struct {
> @@ -989,11 +992,18 @@ static ULONG WINAPI FolderItemsImpl_Release(FolderItems3 *iface)
>  {
>      FolderItemsImpl *This = impl_from_FolderItems(iface);
>      ULONG ref = InterlockedDecrement(&This->ref);
> +    int i;
>  
>      TRACE("(%p), new refcount=%i\n", iface, ref);
>  
>      if (!ref)
> +    {
> +        VariantClear(&This->dir);
> +        for (i = 0; i < This->item_count; i++)
> +            SysFreeString(This->item_paths[i]);
> +        HeapFree(GetProcessHeap(), 0, This->item_paths);
>          HeapFree(GetProcessHeap(), 0, This);
> +    }
>      return ref;
>  }
>  
> @@ -1079,10 +1089,47 @@ static HRESULT WINAPI FolderItemsImpl_get_Parent(FolderItems3 *iface, IDispatch
>  
>  static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **ppid)
>  {
> -    FIXME("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid);
> +    FolderItemsImpl *This = impl_from_FolderItems(iface);
> +    VARIANT path;
> +    int i;
> +
> +    TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid);
>  
>      *ppid = NULL;
> -    return E_NOTIMPL;
> +
> +    switch (V_VT(&index))
> +    {
> +        case VT_I2:
> +            VariantChangeType(&index, &index, 0, VT_I4);
> +            /* fall through */
> +        case VT_I4:
> +            if (V_I4(&index) < 0 || V_I4(&index) >= This->item_count)
> +                return S_FALSE;
> +
> +            V_VT(&path) = VT_BSTR;
> +            V_BSTR(&path) = This->item_paths[V_I4(&index)];
> +            return FolderItem_Constructor(&path, ppid);
> +
> +        case VT_BSTR:
> +            for (i = 0; i < This->item_count; i++)
> +            {
> +                if (!lstrcmpW(V_BSTR(&index), PathFindFileNameW(This->item_paths[i])))

Usually strcmpW is preferred in Wine code. Its better to do NULL pointer
checks explicitly.

> +                {
> +                    V_VT(&path) = VT_BSTR;
> +                    V_BSTR(&path) = This->item_paths[i];
> +                    return FolderItem_Constructor(&path, ppid);
> +                }
> +            }
> +            return S_FALSE;
> +
> +        case VT_ERROR:
> +            V_VT(&path) = VT_BSTR;
> +            V_BSTR(&path) = V_BSTR(&This->dir);
> +            return FolderItem_Constructor(&path, ppid);

You can also pass &This->dir directly to the constructor.

> +
> +        default:
> +            return E_NOTIMPL;
> +    }
>  }
>  
>  static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk)
> @@ -1139,21 +1186,93 @@ static const FolderItems3Vtbl FolderItemsImpl_Vtbl = {
>      FolderItemsImpl_get_Verbs
>  };
>  
> -static HRESULT FolderItems_Constructor(FolderItems **ppfi)
> +static HRESULT FolderItems_Constructor(VARIANT *dir, FolderItems **ppfi)
>  {
> +    static const WCHAR backslash_star[] = {'\\','*',0};
> +    static const WCHAR dot[] = {'.',0};
> +    static const WCHAR dot_dot[] = {'.','.',0};
>      FolderItemsImpl *This;
> +    WCHAR path[MAX_PATH + 2];
> +    HANDLE first_file;
> +    WIN32_FIND_DATAW file_info;
> +    BSTR *paths;
> +    HRESULT ret;
>  
>      TRACE("\n");

Not really an issue, but you could add a trace for the function arguments here.

>  
>      *ppfi = NULL;
>  
> +    if (V_VT(dir) == VT_I4)
> +    {
> +        FIXME("special folder constants are not supported\n");
> +        return E_NOTIMPL;
> +    }
> +
>      This = HeapAlloc(GetProcessHeap(), 0, sizeof(FolderItemsImpl));
>      if (!This) return E_OUTOFMEMORY;
>      This->FolderItems3_iface.lpVtbl = &FolderItemsImpl_Vtbl;
>      This->ref = 1;
>  
> +    VariantInit(&This->dir);
> +    ret = VariantCopy(&This->dir, dir);
> +    if (FAILED(ret))
> +    {
> +        HeapFree(GetProcessHeap(), 0, This);
> +        return E_OUTOFMEMORY;
> +    }
> +
> +    This->item_paths = HeapAlloc(GetProcessHeap(), 0, sizeof(BSTR));
> +    if (!This->item_paths)
> +    {
> +        VariantClear(&This->dir);
> +        HeapFree(GetProcessHeap(), 0, This);
> +        return E_OUTOFMEMORY;
> +    }
> +    This->item_count = 0;
> +
> +    lstrcpyW(path, V_BSTR(dir));
> +    lstrcatW(path, backslash_star);
> +    first_file = FindFirstFileW(path, &file_info);
> +    if (first_file != INVALID_HANDLE_VALUE)
> +    {
> +        do
> +        {
> +            if (!lstrcmpW(file_info.cFileName, dot) || !lstrcmpW(file_info.cFileName, dot_dot))
> +                continue;

Similar to above, strcmpW is usually preferred.

> +
> +            if (!PathCombineW(path, V_BSTR(dir), file_info.cFileName))
> +            {
> +                ret = E_OUTOFMEMORY;
> +                goto fail;
> +            }

I think it makes more sense to store the relative paths, there is no
need to prepend the directory name in advance. FolderItemsImpl_Item
also expects a relative path for example.

> +
> +            paths = HeapReAlloc(GetProcessHeap(), 0, This->item_paths, (This->item_count + 1) * sizeof(BSTR));

It seems more reasonable to increase the buffer size in bigger chunks.
Its better to have a few entries overhead than to do frequent reallocs.

> +            if (!paths)
> +            {
> +                ret = E_OUTOFMEMORY;
> +                goto fail;
> +            }
> +            This->item_paths = paths;
> +
> +            This->item_paths[This->item_count] = SysAllocString(path);
> +            if (!This->item_paths[This->item_count])
> +            {
> +                ret = E_OUTOFMEMORY;
> +                goto fail;
> +            }
> +            This->item_count++;
> +        }
> +        while (FindNextFileW(first_file, &file_info));
> +
> +        FindClose(first_file);
> +    }
> +
>      *ppfi = (FolderItems*)&This->FolderItems3_iface;
> -    return S_OK;
> +    return ret;

It is better to return S_OK explicitly because !FAILED(ret) could still be
any other value >= 0, like S_FALSE for example.

> +
> +fail:

You are leaking the FindFirstFile handle here.

> +    FolderItems3_Release(&This->FolderItems3_iface);
> +    return ret;
>  }
>  
>  static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid,
> @@ -1308,9 +1427,11 @@ static HRESULT WINAPI FolderImpl_get_ParentFolder(Folder3 *iface, Folder **ppsf)
>  
>  static HRESULT WINAPI FolderImpl_Items(Folder3 *iface, FolderItems **ppid)
>  {
> -    FIXME("(%p,%p)\n", iface, ppid);
> +    FolderImpl *This = impl_from_Folder(iface);
> +
> +    TRACE("(%p,%p)\n", iface, ppid);
>  
> -    return FolderItems_Constructor(ppid);
> +    return FolderItems_Constructor(&This->dir, ppid);
>  }
>  
>  static HRESULT WINAPI FolderImpl_ParseName(Folder3 *iface, BSTR name, FolderItem **item)
> diff --git a/dlls/shell32/tests/shelldispatch.c b/dlls/shell32/tests/shelldispatch.c
> index 6715794..dc4fda4 100644
> --- a/dlls/shell32/tests/shelldispatch.c
> +++ b/dlls/shell32/tests/shelldispatch.c
> @@ -390,7 +390,6 @@ todo_wine
>          r = FolderItems_Item(items, var, NULL);
>  
>      r = FolderItems_Item(items, var, &item);
> -todo_wine
>      ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
>      ok(!item, "item is not null\n");
>  
> @@ -470,14 +469,11 @@ todo_wine
>          r = FolderItems_Item(items, var, &item);
>          if (i == VT_I2 || i == VT_I4 || i == VT_ERROR)
>          {
> -todo_wine
>              ok(r == S_OK, "type %d: expected S_OK, got %08x\n", i, r);
> -todo_wine
>              ok(!!item, "item is null\n");
>          }
>          else if (i == VT_BSTR)
>          {
> -todo_wine
>              ok(r == S_FALSE, "type %d: expected S_FALSE, got %08x\n", i, r);
>              ok(!item, "item is not null\n");
>          }
> @@ -495,11 +491,8 @@ todo_wine
>          V_VT(&var) = VT_ERROR;
>          V_ERROR(&var) = i;
>          r = FolderItems_Item(items, var, &item);
> -todo_wine
>          ok(r == S_OK, "expected S_OK, got %08x\n", r);
> -todo_wine
>          ok(!!item, "item is null\n");
> -        if (!item) continue;
>  
>          bstr = NULL;
>          r = FolderItem_get_Path(item, &bstr);
> @@ -518,7 +511,6 @@ todo_wine
>      V_I4(&var) = -1;
>      item = (FolderItem*)0xdeadbeef;
>      r = FolderItems_Item(items, var, &item);
> -todo_wine
>      ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
>      ok(!item, "item is not null\n");
>  
> @@ -541,11 +533,8 @@ todo_wine
>  
>              item = NULL;
>              r = FolderItems_Item(items, var, &item);
> -todo_wine
>              ok(r == S_OK, "file_defs[%d], %d: FolderItems::Item failed: %08x\n", i, j, r);
> -todo_wine
>              ok(!!item, "file_defs[%d], %d: item is null\n", i, j);
> -            if (!item) continue;
>  
>              item2 = NULL;
>              r = FolderItems_Item(items, var, &item2);
> @@ -572,7 +561,6 @@ todo_wine
>      V_I4(&var) = sizeof(file_defs)/sizeof(file_defs[0]);
>      item = (FolderItem*)0xdeadbeef;
>      r = FolderItems_Item(items, var, &item);
> -todo_wine
>      ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
>      ok(!item, "item is not null\n");
>  
> 




More information about the wine-devel mailing list