|
Hi Furty
As far as I could see, no one gave the solution to the Folder --> FolderItem problem. The last I saw was the ParentFolder.Items loop.
Well, you where right, there is a shorter way, and it comes from using Shell32.dll version 5.0 or later on win-2000 & Millennium. (I see that the Interop.Shell32 you attached to the demo, is from this version).
So this is the function I added to the ShellOperations class in FolderTreeView.cs:
public static Shell32.FolderItem GetFolderItemFromFolder(Shell32.Folder folder)
{
if(folder != null)
{
try
{
IntPtr fldPtr = <a target=_blank title='New Window' href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemruntimeinteropservicesmarshalclassgetcominterfaceforobjecttopic.asp">Marshal.GetComInterfaceForObject</a>(folder, typeof(Shell32.Folder2));
Shell32.Folder2 fldr2 = (Shell32.Folder2)<a target=_blank title='New Window' href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemruntimeinteropservicesmarshalclassgetobjectforiunknowntopic.asp">Marshal.GetObjectForIUnknown</a>(fldPtr);
return <a target=_blank title='New Window' href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/objects/folder2/self.asp">fldr2.Self</a>;
}
catch{}
return null;
}
return null;
}
REMEMBER: This method might return null, if you do not have the right Shell32 version.
Now, that I have this short-cut, I changed the way DrillTree works.
The first change is in the way I think about locating the Tree-Path. I say, instead of looking from the root, lets start from the leaf.
We’ll get the folder using Shell.NameSpace, and fill a list with the Folder we found, and all its’ parent folders.
Then we’ll iterate backward in the list and forward in the tree, until we have the right node.
This is made out of two functions:
DrillToFolderByShell , replaces the original DrillToFolder we have now.
DrillTreeByFolderList , is the recursive TreeNode seek, the DrillToFolderByShell uses.
Both function are implemented in the FolderTreeView class .
DrillToFolderByShell:
public bool DrillToFolderByShell(string folderPath)
{
Shell32.Shell shell32 = new Shell32.ShellClass();
Shell32.Folder shell32Folder = shell32.NameSpace(folderPath);
if(shell32Folder != null)
{
ArrayList fullLst = new ArrayList();
fullLst.Add(shell32Folder);
Shell32.Folder par = shell32Folder.ParentFolder;
while(par != null)
{
fullLst.Add(par);
par = par.ParentFolder;
}
SelectedNode = DrillTreeByFolderList(Nodes, fullLst);
return SelectedNode != null;
}
else
throw new DirectoryNotFoundException("\"" + folderPath + "\" Not found");
}
DrillTreeByFolderList
private TreeNode DrillTreeByFolderList(TreeNodeCollection tnLst, ArrayList folderList)
{
Shell32.Folder seekFolder = folderList[titleList.Count - 1] as Shell32.Folder;
folderList.RemoveAt(titleList.Count - 1);
string s1 = seekFolder.Title;
Shell32.FolderItem seekFldItem = ShellOperations.GetFolderItemFromFolder(seekFolder);
if(seekFldItem != null)
s1 = seekFldItem.Name;
foreach(TreeNode tn in tnLst)
{
Shell32.FolderItem curFolder = (Shell32.FolderItem)tn.Tag;
string s2 = curFolder.Name;
if((String.Compare(s1, s2, true) == 0))
{
tn.Expand();
if(titleList.Count > 0)
return DrillTreeByTitleList(tn.Nodes, titleList);
else
return tn;
}
}
return null;
}
And this is it.
P.S. .NET 1.1 includes the DirectoryDialogBox, and I think that the Shell32 controls are close (if not included already). So all of this might be purely educational at the end.
Ittay
|
|
|
|
|
Thanks for the heads up Ittay, I will be updating the article and code as soon as I get through my current workload...
|
|
|
|
|
First of all, this is an excellent control. I have tested quite a few other folder tree view controls, but being a pure (more or less) .NET control, this one is really easy to extend and use in my .NET projects. Thanks, Furty!!
Now, there is a small issue with it; It lists all zip-files on my desktop. For all other folders, zip-files are not listed. (As far as I can tell...)
Is this a feature, bug or parameter that I have missed?
Best Regards,
Terje Krång, terje@dreamscape.no
|
|
|
|
|
Well, i cant answer to whether he deliberatley coded for this at all in his control. However, i can tell you that in WinXP, zip files are (for the most part) considered and treated as folders.
If you notice, when you dbl-click a zip, it opens a normal explorer window, not a zip program (unless youve changed that yourself).
This is probably why youre seeing this behaviour.
|
|
|
|
|
To stop zip files being listed under the Desktop node change line 452 from this:
if(item.IsFolder)
to this:
if( folderItem.IsFolder && !folderItem.IsBrowsable )
|
|
|
|
|
Could you explain how to use that Shell32.dll thing? I try to build a treeview control using your code you put up there, but I got a bunch of compile errors on Shell32. What reference should I have in order to use it?
Thanks.
|
|
|
|
|
Project -> Add Reference -> COM -> Browse (browse to C:\windows\system32\shell32.dll) select it, then compile
|
|
|
|
|
Could you tell me about "Furty.Windows.Forms.Form TreeView1 "?
And Where is Furty class ? in my computer ?
Thank you very much
|
|
|
|
|
Err, it's in the downloads at the top of the page.
|
|
|
|
|
Great. Haven't tried it out but looks good. I'm not sure if I overlooked something, but when I first tried adding this to my project it had problems with the Shell32 namespace. I figured I had to add a reference to Shell32.dll since I had skimmed the code and somewhere saw "[DllImport(Shell32.dll)]". I quickly perused the COM dlls to import and could not find it. Eventually I just browsed to the dll (after I searched) to find it.
Anyway, it would be cool if there was some documentation or if it mentioned this somewhere in the control description. If I missed it then please ignore this. Otherwise, it would probably be useful for newbies (like me) who might not be familiar with interop and referencing COM dlls (as well as where to find them).
|
|
|
|
|
Thats it. Any links would be appreciated.
Sincerely yours, Ilya Kalujny.
|
|
|
|
|
The demo program looks great, but when I compile the source and run it, the icons all have a shadowed background. Anyone have any ideas?
|
|
|
|
|
|
Tried to follow the direction at that link. Found out I had to sign my exe, the dll with the control, and then the interop.shell32.dll (that was the hard one to figure out, you have to go to product properties to specify a key).
After all was said and done I still have the black borders. My first thought is "I did something wrong, let me add some other contols and see if they are in XP style" so I switched to design view and even it's broken (tells me that there is an error, and to correct it). No idea about the error except the HRESULT and that doesn't help me much.
After all is said and done I'd really rather just figure out a way to make the icons look decent with the old style controls. Any idea on how to do this?
|
|
|
|
|
It's a lot easier with a manifest file.
Copy the following into a text file (notepad works great) called "FolderTreeView.exe.manifest" and put it in the same directory as the FolderTreeView.exe file.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
processorArchitecture="x86"
version="5.1.0.0"
type="win32"
name="FolderTreeView.exe"/>
<description>Folder Tree View</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="x86"/>
</dependentAssembly>
</dependency>
</assembly>
<small><a style='color:black'>Help! I'm an AI running around in someone's f*cked up universe simulator.</a><br>Sensitivity and ethnic diversity means celebrating difference, not hiding from it. - Christian Graus<br>Every line of code is a liability - Taka Muraoka<br>Microsoft deliberately adds arbitrary layers of complexity to make it difficult to deliver Windows features on non-Windows platforms--Microsoft's "Halloween files"</small>
|
|
|
|
|
Thanks for the wonderful control. I am trying to use this in a project I am working on, but I need to be able to show all files and folders on the filesystem. I have modified the control to show files as well as folders, but I am not sure how to make it show hidden folders/files. Any help would be appreciated.
Thanks,
Scott
|
|
|
|
|
Hy Scott
is it easy to show files as well as folders? Can you show me the way?
Thx,
Peter
|
|
|
|
|
To show hidden folders, you need to modify the file FolderTreeView.cs by replacing line 523
foreach(Shell32.FolderItem item in folder.Items())
with
Shell32.FolderItems3 items = (Shell32.FolderItems3 )folder.Items();
int SHCONTF_INCLUDEHIDDEN = 128;
int SHCONTF_FOLDERS = 32;
int SHCONTF_NONFOLDERS = 64;
items.Filter(SHCONTF_INCLUDEHIDDEN | SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, "*");
foreach (Shell32.FolderItem item in items)
...
Version 3 of FolderItems supports this type of filtering.
Jos
modified on Saturday, October 31, 2009 12:51 PM
|
|
|
|
|
Any idea why the "My Documents" icon returned is not the good one ?
Jonathan.
|
|
|
|
|
Congratulation for your control.
I used some of your code in a ExplorerListView component i'm currently developping.
It should be finished very soon.
I will post it here after that, so everyone can use it.
Regards.
|
|
|
|
|
I have a Folder class instance. I need to get the ParentFolder. I tried with the property "PArentFolder" from the Folder class but i need to have a FolderItem for the parent not a Folder. Does somebody knows how to get a FolderItem object from a Fodler object ?
Thanks.
|
|
|
|
|
Ahhh yes, I remember this Here is the code I came up with, it may not be the best way, but it worked for me when looking for the desktop dir, while keeping the vitrual desktop namespace members.
Shell32.Folder dfolder = shell32.NameSpace(ShellFolder.DesktopDirectory);<br />
foreach(Shell32.FolderItem fi in dfolder.ParentFolder.Items())<br />
{<br />
<br />
if(fi.Name == dfolder.Title)<br />
{<br />
myFolderItem = fi;<br />
break;<br />
}<br />
}
if you find a better way, let me know..
|
|
|
|
|
Heh heh,
It's funny we had the same idea I did it like that while i find a better idea.
Looping through all element in large folders (don't forget my component display files too ) is quite "slow". And just for your info, i think it must be a very good idea to try to optimize the icons things. I mean, getting the system image list directly like somebody else suggest you in another thread.
I tested my control in folder having more than 1000 items, and after that returning getting item icon handles (Icon.FromHandle(info.hIcon);) failed for each subsequent item...
I'll try to find a way to optimize that.
Thanks.
Jonathan
|
|
|
|
|
I'd love to be able to convert, or access the system image list, but my (albeit feeble) efforts to do so have lead nowhere - I wonder if there's any shell guru's out there who want to take on the challenge?
As for your file list view, for now all I can do is give you this piece of code which caches icons by their path into a hashtable. You will probably want to change this to work by file extension rather than path, and add some checks for extensions that have unique icons such as .exe and .lnk
Hope this helps!
<br />
using System;<br />
using System.Collections;<br />
using System.Runtime.InteropServices;<br />
using System.Drawing;<br />
using System.Windows.Forms;<br />
<br />
#region ExtractIcons Class<br />
<br />
public class ExtractIcons<br />
{<br />
private Hashtable shellIcons;<br />
private Hashtable fileIcons;<br />
<br />
#region Constructor<br />
<br />
public ExtractIcons()<br />
{<br />
shellIcons = new Hashtable();<br />
fileIcons = new Hashtable();<br />
}<br />
<br />
#endregion<br />
<br />
#region Structs & Enum<br />
<br />
[StructLayout(LayoutKind.Sequential)]<br />
private struct SHFILEINFO<br />
{<br />
public SHFILEINFO(bool b)<br />
{<br />
hIcon=IntPtr.Zero;iIcon=0;dwAttributes=0;szDisplayName="";szTypeName="";<br />
}<br />
public IntPtr hIcon;<br />
public int iIcon;<br />
public uint dwAttributes;<br />
[MarshalAs(UnmanagedType.LPStr, SizeConst=260)]<br />
public string szDisplayName;<br />
[MarshalAs(UnmanagedType.LPStr, SizeConst=80)]<br />
public string szTypeName;<br />
};<br />
<br />
private enum SHGFI<br />
{<br />
SHGFI_ICON = 0x000000100,
SHGFI_DISPLAYNAME = 0x000000200,
SHGFI_TYPENAME = 0x000000400,
SHGFI_ATTRIBUTES = 0x000000800,
SHGFI_ICONLOCATION = 0x000001000,
SHGFI_EXETYPE = 0x000002000,
SHGFI_SYSICONINDEX = 0x000004000,
SHGFI_LINKOVERLAY = 0x000008000,
SHGFI_SELECTED = 0x000010000,
SHGFI_ATTR_SPECIFIED = 0x000020000,
SHGFI_LARGEICON = 0x000000000,
SHGFI_SMALLICON = 0x000000001,
SHGFI_OPENICON = 0x000000002,
SHGFI_SHELLICONSIZE = 0x000000004,
SHGFI_PIDL = 0x000000008,
SHGFI_USEFILEATTRIBUTES = 0x000000010
}<br />
<br />
#endregion<br />
<br />
#region Get File / Folder Icons<br />
<br />
<br />
[DllImport("Shell32.dll")]<br />
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, <br />
out SHFILEINFO psfi, uint cbfileInfo, SHGFI uFlags );<br />
<br />
public int GetIcon(string strPath, bool large, bool selected, ImageList imageList)<br />
{<br />
if(fileIcons.ContainsKey(strPath + large.ToString()))<br />
{<br />
imageList.Images.Add((Icon)fileIcons[strPath + large.ToString()]);<br />
return imageList.Images.Count - 1;<br />
}<br />
else<br />
{<br />
try<br />
{<br />
SHFILEINFO info = new SHFILEINFO(true);<br />
int cbFileInfo = Marshal.SizeOf(info);<br />
SHGFI flags;<br />
if(large)<br />
{<br />
if (!selected)<br />
flags = SHGFI.SHGFI_ICON|SHGFI.SHGFI_LARGEICON;<br />
else<br />
flags = SHGFI.SHGFI_ICON|SHGFI.SHGFI_LARGEICON|SHGFI.SHGFI_OPENICON;<br />
}<br />
else<br />
{<br />
if (!selected)<br />
flags = SHGFI.SHGFI_ICON|SHGFI.SHGFI_SMALLICON;<br />
else<br />
flags = SHGFI.SHGFI_ICON|SHGFI.SHGFI_SMALLICON|SHGFI.SHGFI_OPENICON;<br />
}<br />
<br />
SHGetFileInfo(strPath, 256, out info,(uint)cbFileInfo, flags);<br />
<br />
Icon icn;<br />
icn = (Icon)Icon.FromHandle(info.hIcon).Clone();<br />
User32.DestroyIcon( info.hIcon ); <br />
<br />
fileIcons.Add(strPath + large.ToString(), icn);<br />
<br />
imageList.Images.Add(icn);<br />
return imageList.Images.Count - 1;<br />
}<br />
catch<br />
{<br />
return -1;<br />
}<br />
}<br />
}<br />
<br />
#endregion<br />
<br />
#region Get Specific Shell Icon<br />
<br />
<br />
[DllImport("Shell32.dll", CharSet=CharSet.Auto)]<br />
private static extern int ExtractIconEx(<br />
string lpszFile, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, int nIcons );<br />
<br />
public Icon GetShellIcon(int iconIndex)<br />
{<br />
if(shellIcons.ContainsKey(iconIndex))<br />
{<br />
return (Icon)shellIcons[iconIndex];<br />
}<br />
else<br />
{<br />
Icon icn;<br />
IntPtr[] handlesIconLarge = new IntPtr[1];<br />
IntPtr[] handlesIconSmall = new IntPtr[1];<br />
int i = ExtractIconEx(Environment.SystemDirectory + "\\shell32.dll", iconIndex, <br />
handlesIconLarge, handlesIconSmall, 1);<br />
if(handlesIconSmall.Length > 0 && handlesIconSmall[0] != IntPtr.Zero)<br />
{<br />
icn = (Icon)Icon.FromHandle(handlesIconSmall[0]).Clone();<br />
User32.DestroyIcon( handlesIconSmall[0] ); <br />
}<br />
else<br />
{<br />
icn = null;<br />
}<br />
shellIcons.Add(iconIndex, icn);<br />
return icn;<br />
}<br />
}<br />
<br />
#endregion<br />
<br />
}<br />
<br />
#region Destroy Icon<br />
public class User32<br />
{<br />
[DllImport("User32.dll")]<br />
public static extern int DestroyIcon( IntPtr hIcon );<br />
}<br />
#endregion<br />
<br />
#endregion<br />
|
|
|
|
|
:confusedconfusedHi all.
I want a right to left treeview for a right to left treeview.
is anyone to help me.
thanks.
|
|
|
|
|