shell32: Use shellfolder API to construct FolderItems.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5fa8713ddc
commit
7c638b00c7
|
@ -73,7 +73,7 @@ typedef struct {
|
||||||
FolderItems3 FolderItems3_iface;
|
FolderItems3 FolderItems3_iface;
|
||||||
LONG ref;
|
LONG ref;
|
||||||
FolderImpl *folder;
|
FolderImpl *folder;
|
||||||
WCHAR **item_filenames;
|
WCHAR **item_names;
|
||||||
LONG item_count;
|
LONG item_count;
|
||||||
} FolderItemsImpl;
|
} FolderItemsImpl;
|
||||||
|
|
||||||
|
@ -1023,8 +1023,8 @@ static ULONG WINAPI FolderItemsImpl_Release(FolderItems3 *iface)
|
||||||
{
|
{
|
||||||
Folder3_Release(&This->folder->Folder3_iface);
|
Folder3_Release(&This->folder->Folder3_iface);
|
||||||
for (i = 0; i < This->item_count; i++)
|
for (i = 0; i < This->item_count; i++)
|
||||||
HeapFree(GetProcessHeap(), 0, This->item_filenames[i]);
|
HeapFree(GetProcessHeap(), 0, This->item_names[i]);
|
||||||
HeapFree(GetProcessHeap(), 0, This->item_filenames);
|
HeapFree(GetProcessHeap(), 0, This->item_names);
|
||||||
HeapFree(GetProcessHeap(), 0, This);
|
HeapFree(GetProcessHeap(), 0, This);
|
||||||
}
|
}
|
||||||
return ref;
|
return ref;
|
||||||
|
@ -1111,16 +1111,16 @@ static HRESULT WINAPI FolderItemsImpl_get_Parent(FolderItems3 *iface, IDispatch
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **ppid)
|
static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **item)
|
||||||
{
|
{
|
||||||
FolderItemsImpl *This = impl_from_FolderItems(iface);
|
FolderItemsImpl *This = impl_from_FolderItems(iface);
|
||||||
WCHAR canonicalized_index[MAX_PATH], path_str[MAX_PATH];
|
WCHAR buffW[MAX_PATH], *display_name;
|
||||||
VARIANT path_var;
|
HRESULT hr;
|
||||||
HRESULT ret;
|
VARIANT v;
|
||||||
|
|
||||||
TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), ppid);
|
TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), item);
|
||||||
|
|
||||||
*ppid = NULL;
|
*item = NULL;
|
||||||
|
|
||||||
if (!PathIsDirectoryW(V_BSTR(&This->folder->dir)))
|
if (!PathIsDirectoryW(V_BSTR(&This->folder->dir)))
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
@ -1135,41 +1135,41 @@ static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, F
|
||||||
if (V_I4(&index) >= This->item_count || V_I4(&index) < 0)
|
if (V_I4(&index) >= This->item_count || V_I4(&index) < 0)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
if (!PathCombineW(path_str, V_BSTR(&This->folder->dir), This->item_filenames[V_I4(&index)]))
|
display_name = This->item_names[V_I4(&index)];
|
||||||
return S_FALSE;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VT_BSTR:
|
case VT_BSTR:
|
||||||
|
{
|
||||||
|
LPITEMIDLIST pidl;
|
||||||
|
STRRET strret;
|
||||||
|
|
||||||
if (!V_BSTR(&index))
|
if (!V_BSTR(&index))
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
if (!PathCanonicalizeW(canonicalized_index, V_BSTR(&index)))
|
if (FAILED(hr = IShellFolder2_ParseDisplayName(This->folder->folder, NULL, NULL, V_BSTR(&index),
|
||||||
|
NULL, &pidl, NULL)))
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
if (strcmpW(V_BSTR(&index), canonicalized_index) != 0)
|
IShellFolder2_GetDisplayNameOf(This->folder->folder, pidl, SHGDN_FORPARSING, &strret);
|
||||||
return S_FALSE;
|
StrRetToBufW(&strret, NULL, buffW, sizeof(buffW)/sizeof(*buffW));
|
||||||
|
ILFree(pidl);
|
||||||
if (!PathCombineW(path_str, V_BSTR(&This->folder->dir), V_BSTR(&index)))
|
|
||||||
return S_FALSE;
|
|
||||||
|
|
||||||
if (!PathFileExistsW(path_str))
|
|
||||||
return S_FALSE;
|
|
||||||
|
|
||||||
|
display_name = buffW;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case VT_ERROR:
|
case VT_ERROR:
|
||||||
return FolderItem_Constructor(This->folder, &This->folder->dir, ppid);
|
return FolderItem_Constructor(This->folder, &This->folder->dir, item);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
FIXME("Index type %d not handled.\n", V_VT(&index));
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
V_VT(&path_var) = VT_BSTR;
|
V_VT(&v) = VT_BSTR;
|
||||||
V_BSTR(&path_var) = SysAllocString(path_str);
|
V_BSTR(&v) = SysAllocString(display_name);
|
||||||
ret = FolderItem_Constructor(This->folder, &path_var, ppid);
|
hr = FolderItem_Constructor(This->folder, &v, item);
|
||||||
VariantClear(&path_var);
|
VariantClear(&v);
|
||||||
return ret;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk)
|
static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk)
|
||||||
|
@ -1226,21 +1226,49 @@ static const FolderItems3Vtbl FolderItemsImpl_Vtbl = {
|
||||||
FolderItemsImpl_get_Verbs
|
FolderItemsImpl_get_Verbs
|
||||||
};
|
};
|
||||||
|
|
||||||
static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ppfi)
|
static void idlist_sort(LPITEMIDLIST *idlist, unsigned int l, unsigned int r, IShellFolder2 *folder)
|
||||||
{
|
{
|
||||||
static const WCHAR backslash_star[] = {'\\','*',0};
|
unsigned int m;
|
||||||
static const WCHAR dot[] = {'.',0};
|
|
||||||
static const WCHAR dot_dot[] = {'.','.',0};
|
if (l == r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (r < l)
|
||||||
|
{
|
||||||
|
idlist_sort(idlist, r, l, folder);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = (l + r) / 2;
|
||||||
|
idlist_sort(idlist, l, m, folder);
|
||||||
|
idlist_sort(idlist, m + 1, r, folder);
|
||||||
|
|
||||||
|
/* join the two sides */
|
||||||
|
while (l <= m && m < r)
|
||||||
|
{
|
||||||
|
if ((short)IShellFolder2_CompareIDs(folder, 0, idlist[l], idlist[m + 1]) > 0)
|
||||||
|
{
|
||||||
|
LPITEMIDLIST t = idlist[m + 1];
|
||||||
|
memmove(&idlist[l + 1], &idlist[l], (m - l + 1) * sizeof(idlist[l]));
|
||||||
|
idlist[l] = t;
|
||||||
|
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ret)
|
||||||
|
{
|
||||||
|
IEnumIDList *enumidlist;
|
||||||
FolderItemsImpl *This;
|
FolderItemsImpl *This;
|
||||||
LONG item_size;
|
LPITEMIDLIST pidl;
|
||||||
WCHAR glob[MAX_PATH + 2];
|
unsigned int i;
|
||||||
HANDLE first_file;
|
HRESULT hr;
|
||||||
WIN32_FIND_DATAW file_info;
|
|
||||||
WCHAR **filenames;
|
|
||||||
|
|
||||||
TRACE("(%s,%p)\n", debugstr_variant(&folder->dir), ppfi);
|
TRACE("(%s,%p)\n", debugstr_variant(&folder->dir), ret);
|
||||||
|
|
||||||
*ppfi = NULL;
|
*ret = NULL;
|
||||||
|
|
||||||
if (V_VT(&folder->dir) == VT_I4)
|
if (V_VT(&folder->dir) == VT_I4)
|
||||||
{
|
{
|
||||||
|
@ -1248,61 +1276,68 @@ static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ppfi)
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
This = HeapAlloc(GetProcessHeap(), 0, sizeof(FolderItemsImpl));
|
This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
|
||||||
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;
|
||||||
This->folder = folder;
|
This->folder = folder;
|
||||||
Folder3_AddRef(&folder->Folder3_iface);
|
Folder3_AddRef(&folder->Folder3_iface);
|
||||||
|
|
||||||
This->item_count = 0;
|
enumidlist = NULL;
|
||||||
lstrcpyW(glob, V_BSTR(&folder->dir));
|
if (FAILED(hr = IShellFolder2_EnumObjects(folder->folder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,
|
||||||
lstrcatW(glob, backslash_star);
|
&enumidlist)))
|
||||||
first_file = FindFirstFileW(glob, &file_info);
|
|
||||||
if (first_file != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
{
|
||||||
item_size = 128;
|
goto failed;
|
||||||
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);
|
while (IEnumIDList_Next(enumidlist, 1, &pidl, NULL) == S_OK)
|
||||||
if (!This->item_filenames[This->item_count])
|
{
|
||||||
goto fail;
|
|
||||||
This->item_count++;
|
This->item_count++;
|
||||||
|
ILFree(pidl);
|
||||||
}
|
}
|
||||||
while (FindNextFileW(first_file, &file_info));
|
|
||||||
|
|
||||||
FindClose(first_file);
|
if (This->item_count)
|
||||||
HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
|
|
||||||
This->item_filenames, This->item_count * sizeof(WCHAR*));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
This->item_filenames = NULL;
|
LPITEMIDLIST *pidls = HeapAlloc(GetProcessHeap(), 0, This->item_count * sizeof(*pidls));
|
||||||
|
This->item_names = HeapAlloc(GetProcessHeap(), 0, This->item_count * sizeof(*This->item_names));
|
||||||
|
|
||||||
|
if (!pidls || !This->item_names)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, pidls);
|
||||||
|
HeapFree(GetProcessHeap(), 0, This->item_names);
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ppfi = (FolderItems*)&This->FolderItems3_iface;
|
IEnumIDList_Reset(enumidlist);
|
||||||
|
if (IEnumIDList_Next(enumidlist, This->item_count, pidls, NULL) == S_OK)
|
||||||
|
idlist_sort(pidls, 0, This->item_count - 1, folder->folder);
|
||||||
|
|
||||||
|
for (i = 0; i < This->item_count; i++)
|
||||||
|
{
|
||||||
|
WCHAR buffW[MAX_PATH];
|
||||||
|
STRRET strret;
|
||||||
|
|
||||||
|
IShellFolder2_GetDisplayNameOf(folder->folder, pidls[i], SHGDN_FORPARSING, &strret);
|
||||||
|
StrRetToBufW(&strret, NULL, buffW, sizeof(buffW)/sizeof(*buffW));
|
||||||
|
|
||||||
|
This->item_names[i] = strdupW(buffW);
|
||||||
|
|
||||||
|
ILFree(pidls[i]);
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, pidls);
|
||||||
|
}
|
||||||
|
IEnumIDList_Release(enumidlist);
|
||||||
|
|
||||||
|
*ret = (FolderItems *)&This->FolderItems3_iface;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
fail:
|
failed:
|
||||||
FindClose(first_file);
|
if (enumidlist)
|
||||||
FolderItems3_Release(&This->FolderItems3_iface);
|
IEnumIDList_Release(enumidlist);
|
||||||
return E_OUTOFMEMORY;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid,
|
static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid,
|
||||||
|
|
|
@ -653,8 +653,11 @@ static void test_items(void)
|
||||||
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);
|
||||||
|
}
|
||||||
|
if (item2) FolderItem_Release(item2);
|
||||||
VariantClear(&str_index2);
|
VariantClear(&str_index2);
|
||||||
|
|
||||||
/* remove the directory */
|
/* remove the directory */
|
||||||
|
|
Loading…
Reference in New Issue