shell32: Implement FolderItems_Item.
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
02efd35ce2
commit
93dd50666f
|
@ -68,6 +68,9 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FolderItems3 FolderItems3_iface;
|
FolderItems3 FolderItems3_iface;
|
||||||
LONG ref;
|
LONG ref;
|
||||||
|
VARIANT dir;
|
||||||
|
WCHAR **item_filenames;
|
||||||
|
LONG item_count;
|
||||||
} FolderItemsImpl;
|
} FolderItemsImpl;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -989,11 +992,18 @@ static ULONG WINAPI FolderItemsImpl_Release(FolderItems3 *iface)
|
||||||
{
|
{
|
||||||
FolderItemsImpl *This = impl_from_FolderItems(iface);
|
FolderItemsImpl *This = impl_from_FolderItems(iface);
|
||||||
ULONG ref = InterlockedDecrement(&This->ref);
|
ULONG ref = InterlockedDecrement(&This->ref);
|
||||||
|
LONG i;
|
||||||
|
|
||||||
TRACE("(%p), new refcount=%i\n", iface, ref);
|
TRACE("(%p), new refcount=%i\n", iface, ref);
|
||||||
|
|
||||||
if (!ref)
|
if (!ref)
|
||||||
|
{
|
||||||
|
VariantClear(&This->dir);
|
||||||
|
for (i = 0; i < This->item_count; i++)
|
||||||
|
HeapFree(GetProcessHeap(), 0, This->item_filenames[i]);
|
||||||
|
HeapFree(GetProcessHeap(), 0, This->item_filenames);
|
||||||
HeapFree(GetProcessHeap(), 0, This);
|
HeapFree(GetProcessHeap(), 0, This);
|
||||||
|
}
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,10 +1089,63 @@ static HRESULT WINAPI FolderItemsImpl_get_Parent(FolderItems3 *iface, IDispatch
|
||||||
|
|
||||||
static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **ppid)
|
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);
|
||||||
|
WCHAR canonicalized_index[MAX_PATH], path_str[MAX_PATH];
|
||||||
|
VARIANT path_var;
|
||||||
|
HRESULT ret;
|
||||||
|
|
||||||
|
TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid);
|
||||||
|
|
||||||
*ppid = NULL;
|
*ppid = NULL;
|
||||||
return E_NOTIMPL;
|
|
||||||
|
if (!PathIsDirectoryW(V_BSTR(&This->dir)))
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
switch (V_VT(&index))
|
||||||
|
{
|
||||||
|
case VT_I2:
|
||||||
|
VariantChangeType(&index, &index, 0, VT_I4);
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
|
case VT_I4:
|
||||||
|
if (V_I4(&index) >= This->item_count || V_I4(&index) < 0)
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
if (!PathCombineW(path_str, V_BSTR(&This->dir), This->item_filenames[V_I4(&index)]))
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VT_BSTR:
|
||||||
|
if (!V_BSTR(&index))
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
if (!PathCanonicalizeW(canonicalized_index, V_BSTR(&index)))
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
if (strcmpW(V_BSTR(&index), canonicalized_index) != 0)
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
if (!PathCombineW(path_str, V_BSTR(&This->dir), V_BSTR(&index)))
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
if (!PathFileExistsW(path_str))
|
||||||
|
return S_FALSE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VT_ERROR:
|
||||||
|
return FolderItem_Constructor(&This->dir, ppid);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
V_VT(&path_var) = VT_BSTR;
|
||||||
|
V_BSTR(&path_var) = SysAllocString(path_str);
|
||||||
|
ret = FolderItem_Constructor(&path_var, ppid);
|
||||||
|
VariantClear(&path_var);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk)
|
static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk)
|
||||||
|
@ -1139,21 +1202,90 @@ static const FolderItems3Vtbl FolderItemsImpl_Vtbl = {
|
||||||
FolderItemsImpl_get_Verbs
|
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;
|
FolderItemsImpl *This;
|
||||||
|
LONG item_size;
|
||||||
|
WCHAR glob[MAX_PATH + 2];
|
||||||
|
HANDLE first_file;
|
||||||
|
WIN32_FIND_DATAW file_info;
|
||||||
|
WCHAR **filenames;
|
||||||
|
HRESULT ret;
|
||||||
|
|
||||||
TRACE("\n");
|
TRACE("(%s,%p)\n", debugstr_variant(dir), ppfi);
|
||||||
|
|
||||||
*ppfi = NULL;
|
*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));
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(FolderItemsImpl));
|
||||||
if (!This) return E_OUTOFMEMORY;
|
if (!This) return E_OUTOFMEMORY;
|
||||||
This->FolderItems3_iface.lpVtbl = &FolderItemsImpl_Vtbl;
|
This->FolderItems3_iface.lpVtbl = &FolderItemsImpl_Vtbl;
|
||||||
This->ref = 1;
|
This->ref = 1;
|
||||||
|
|
||||||
|
VariantInit(&This->dir);
|
||||||
|
ret = VariantCopy(&This->dir, dir);
|
||||||
|
if (FAILED(ret))
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, This);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
This->item_count = 0;
|
||||||
|
lstrcpyW(glob, V_BSTR(dir));
|
||||||
|
lstrcatW(glob, backslash_star);
|
||||||
|
first_file = FindFirstFileW(glob, &file_info);
|
||||||
|
if (first_file != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
item_size = 128;
|
||||||
|
This->item_filenames = HeapAlloc(GetProcessHeap(), 0, item_size * sizeof(WCHAR*));
|
||||||
|
if (!This->item_filenames)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!strcmpW(file_info.cFileName, dot) || !strcmpW(file_info.cFileName, dot_dot))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (This->item_count >= item_size)
|
||||||
|
{
|
||||||
|
item_size *= 2;
|
||||||
|
filenames = HeapReAlloc(GetProcessHeap(), 0, This->item_filenames, item_size * sizeof(WCHAR*));
|
||||||
|
if (!filenames)
|
||||||
|
goto fail;
|
||||||
|
This->item_filenames = filenames;
|
||||||
|
}
|
||||||
|
|
||||||
|
This->item_filenames[This->item_count] = strdupW(file_info.cFileName);
|
||||||
|
if (!This->item_filenames[This->item_count])
|
||||||
|
goto fail;
|
||||||
|
This->item_count++;
|
||||||
|
}
|
||||||
|
while (FindNextFileW(first_file, &file_info));
|
||||||
|
|
||||||
|
FindClose(first_file);
|
||||||
|
HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
|
||||||
|
This->item_filenames, This->item_count * sizeof(WCHAR*));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
This->item_filenames = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
*ppfi = (FolderItems*)&This->FolderItems3_iface;
|
*ppfi = (FolderItems*)&This->FolderItems3_iface;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
FindClose(first_file);
|
||||||
|
FolderItems3_Release(&This->FolderItems3_iface);
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid,
|
static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid,
|
||||||
|
@ -1308,9 +1440,11 @@ static HRESULT WINAPI FolderImpl_get_ParentFolder(Folder3 *iface, Folder **ppsf)
|
||||||
|
|
||||||
static HRESULT WINAPI FolderImpl_Items(Folder3 *iface, FolderItems **ppid)
|
static HRESULT WINAPI FolderImpl_Items(Folder3 *iface, FolderItems **ppid)
|
||||||
{
|
{
|
||||||
FIXME("(%p,%p)\n", iface, ppid);
|
FolderImpl *This = impl_from_Folder(iface);
|
||||||
|
|
||||||
return FolderItems_Constructor(ppid);
|
TRACE("(%p,%p)\n", iface, ppid);
|
||||||
|
|
||||||
|
return FolderItems_Constructor(&This->dir, ppid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI FolderImpl_ParseName(Folder3 *iface, BSTR name, FolderItem **item)
|
static HRESULT WINAPI FolderImpl_ParseName(Folder3 *iface, BSTR name, FolderItem **item)
|
||||||
|
|
|
@ -456,7 +456,6 @@ todo_wine
|
||||||
r = FolderItems_Item(items, var, NULL);
|
r = FolderItems_Item(items, var, NULL);
|
||||||
|
|
||||||
r = FolderItems_Item(items, var, &item);
|
r = FolderItems_Item(items, var, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
||||||
ok(!item, "item is not null\n");
|
ok(!item, "item is not null\n");
|
||||||
|
|
||||||
|
@ -494,9 +493,7 @@ todo_wine
|
||||||
variant_set_string(&var, file_defs[0].name);
|
variant_set_string(&var, file_defs[0].name);
|
||||||
item = NULL;
|
item = NULL;
|
||||||
r = FolderItems_Item(items, var, &item);
|
r = FolderItems_Item(items, var, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
|
ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
|
||||||
todo_wine
|
|
||||||
ok(!!item, "item is null\n");
|
ok(!!item, "item is null\n");
|
||||||
if (item) FolderItem_Release(item);
|
if (item) FolderItem_Release(item);
|
||||||
VariantClear(&var);
|
VariantClear(&var);
|
||||||
|
@ -533,9 +530,7 @@ todo_wine
|
||||||
V_I2(&var) = 0;
|
V_I2(&var) = 0;
|
||||||
item = NULL;
|
item = NULL;
|
||||||
r = FolderItems_Item(items, var, &item);
|
r = FolderItems_Item(items, var, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
|
ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
|
||||||
todo_wine
|
|
||||||
ok(!!item, "item is null\n");
|
ok(!!item, "item is null\n");
|
||||||
if (item) FolderItem_Release(item);
|
if (item) FolderItem_Release(item);
|
||||||
|
|
||||||
|
@ -543,16 +538,13 @@ todo_wine
|
||||||
V_I4(&var) = 0;
|
V_I4(&var) = 0;
|
||||||
item = NULL;
|
item = NULL;
|
||||||
r = FolderItems_Item(items, var, &item);
|
r = FolderItems_Item(items, var, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
|
ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
|
||||||
todo_wine
|
|
||||||
ok(!!item, "item is null\n");
|
ok(!!item, "item is null\n");
|
||||||
if (item) FolderItem_Release(item);
|
if (item) FolderItem_Release(item);
|
||||||
|
|
||||||
V_I4(&var) = -1;
|
V_I4(&var) = -1;
|
||||||
item = (FolderItem*)0xdeadbeef;
|
item = (FolderItem*)0xdeadbeef;
|
||||||
r = FolderItems_Item(items, var, &item);
|
r = FolderItems_Item(items, var, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
||||||
ok(!item, "item is not null\n");
|
ok(!item, "item is not null\n");
|
||||||
|
|
||||||
|
@ -560,9 +552,7 @@ todo_wine
|
||||||
V_ERROR(&var) = 0;
|
V_ERROR(&var) = 0;
|
||||||
item = NULL;
|
item = NULL;
|
||||||
r = FolderItems_Item(items, var, &item);
|
r = FolderItems_Item(items, var, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_OK, "expected S_OK, got %08x\n", r);
|
ok(r == S_OK, "expected S_OK, got %08x\n", r);
|
||||||
todo_wine
|
|
||||||
ok(!!item, "item is null\n");
|
ok(!!item, "item is null\n");
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
|
@ -585,11 +575,8 @@ todo_wine
|
||||||
|
|
||||||
item = NULL;
|
item = NULL;
|
||||||
r = FolderItems_Item(items, int_index, &item);
|
r = FolderItems_Item(items, int_index, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
|
ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
|
||||||
todo_wine
|
|
||||||
ok(!!item, "file_defs[%d]: item is null\n", i);
|
ok(!!item, "file_defs[%d]: item is null\n", i);
|
||||||
if (!item) goto cleanup;
|
|
||||||
|
|
||||||
item2 = NULL;
|
item2 = NULL;
|
||||||
r = FolderItems_Item(items, int_index, &item2);
|
r = FolderItems_Item(items, int_index, &item2);
|
||||||
|
@ -620,7 +607,6 @@ todo_wine
|
||||||
|
|
||||||
FolderItem_Release(item);
|
FolderItem_Release(item);
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (file_defs[i].type == DIRECTORY)
|
if (file_defs[i].type == DIRECTORY)
|
||||||
{
|
{
|
||||||
/* test that getting an item object for a file in a subdirectory succeeds */
|
/* test that getting an item object for a file in a subdirectory succeeds */
|
||||||
|
@ -628,9 +614,7 @@ cleanup:
|
||||||
variant_set_string(&str_index2, cstr);
|
variant_set_string(&str_index2, cstr);
|
||||||
item2 = NULL;
|
item2 = NULL;
|
||||||
r = FolderItems_Item(items, str_index2, &item2);
|
r = FolderItems_Item(items, str_index2, &item2);
|
||||||
todo_wine
|
|
||||||
ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
|
ok(r == S_OK, "file_defs[%d]: FolderItems::Item failed: %08x\n", i, r);
|
||||||
todo_wine
|
|
||||||
ok(!!item2, "file_defs[%d]: item is null\n", i);
|
ok(!!item2, "file_defs[%d]: item is null\n", i);
|
||||||
if (item2) FolderItem_Release(item2);
|
if (item2) FolderItem_Release(item2);
|
||||||
VariantClear(&str_index2);
|
VariantClear(&str_index2);
|
||||||
|
@ -645,7 +629,6 @@ todo_wine
|
||||||
variant_set_string(&str_index2, cstr);
|
variant_set_string(&str_index2, cstr);
|
||||||
item2 = (FolderItem*)0xdeadbeef;
|
item2 = (FolderItem*)0xdeadbeef;
|
||||||
r = FolderItems_Item(items, str_index2, &item2);
|
r = FolderItems_Item(items, str_index2, &item2);
|
||||||
todo_wine
|
|
||||||
ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r);
|
ok(r == S_FALSE, "file_defs[%d]: expected S_FALSE, got %08x\n", i, r);
|
||||||
ok(!item2, "file_defs[%d]: item is not null\n", i);
|
ok(!item2, "file_defs[%d]: item is not null\n", i);
|
||||||
VariantClear(&str_index2);
|
VariantClear(&str_index2);
|
||||||
|
@ -657,7 +640,6 @@ todo_wine
|
||||||
{
|
{
|
||||||
ok(DeleteFileA(file_defs[i].name), "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
|
ok(DeleteFileA(file_defs[i].name), "file_defs[%d]: DeleteFile failed: %08x\n", i, GetLastError());
|
||||||
}
|
}
|
||||||
if (!item) continue;
|
|
||||||
|
|
||||||
/* test that the folder item is still accessible by integer index */
|
/* test that the folder item is still accessible by integer index */
|
||||||
item = NULL;
|
item = NULL;
|
||||||
|
@ -688,7 +670,6 @@ todo_wine
|
||||||
V_I4(&int_index) = sizeof(file_defs)/sizeof(file_defs[0]);
|
V_I4(&int_index) = sizeof(file_defs)/sizeof(file_defs[0]);
|
||||||
item = (FolderItem*)0xdeadbeef;
|
item = (FolderItem*)0xdeadbeef;
|
||||||
r = FolderItems_Item(items, int_index, &item);
|
r = FolderItems_Item(items, int_index, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
||||||
ok(!item, "item is not null\n");
|
ok(!item, "item is not null\n");
|
||||||
|
|
||||||
|
@ -765,14 +746,12 @@ todo_wine
|
||||||
V_I4(&int_index) = 0;
|
V_I4(&int_index) = 0;
|
||||||
item = (FolderItem*)0xdeadbeef;
|
item = (FolderItem*)0xdeadbeef;
|
||||||
r = FolderItems_Item(items, int_index, &item);
|
r = FolderItems_Item(items, int_index, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
||||||
ok(!item, "item is not null\n");
|
ok(!item, "item is not null\n");
|
||||||
|
|
||||||
variant_set_string(&str_index, file_defs[0].name);
|
variant_set_string(&str_index, file_defs[0].name);
|
||||||
item = (FolderItem*)0xdeadbeef;
|
item = (FolderItem*)0xdeadbeef;
|
||||||
r = FolderItems_Item(items, str_index, &item);
|
r = FolderItems_Item(items, str_index, &item);
|
||||||
todo_wine
|
|
||||||
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
|
||||||
ok(!item, "item is not null\n");
|
ok(!item, "item is not null\n");
|
||||||
VariantClear(&str_index);
|
VariantClear(&str_index);
|
||||||
|
|
Loading…
Reference in New Issue