|
Geez, i started off using IO namespace, it was too slow (was using windows\system32\ for testing which takes minimum 23 secs), then i used microsoft shell and controls (shell32.dll) which is slower still. this cshitem class obviously uses shell cause the icon sizes r cool, all i have to say is well done. thats alot of code.
I would suggest creating a website with forums for this project alone :>
Seriously, this is like the only fileview/folderview out there that works cool. I have even seen fileviews that only show folders/files (not virtual folders like cPanel) for sale on the net!
Well done! and Thanks for not selling this :>
|
|
|
|
|
Thanks for the feedback.
RE: Performance
There is some Forum discussion about performance in the way early parts of the Forum. My original application that used ExpTree did not have an Explorer-like ListView, but did a large amount of file/directory scanning. If you don't need too many Icons (say just the ones in ExpTree), performance can become an issue (with Icons, the Icon stuff overshadows everything else).
Bottom line -- use of the IL... API routines MAY improve performance in that case, but limits the app to Win2K and above. I have started using a couple of them in the Beta along with a test on OS level to see if they are available. I may extend that in the future.
In the "normal" uses of this library, which do use Icons, SystemImageList manager makes all the difference, and it is very noticable.
Jim Parsells
|
|
|
|
|
Ok. My English is not good , so i'm going to try that you understandme.
If i add a folder under a node that no is root. How i can refresh only that subnode and not all tree.
Sorry my english
pd: excelent control!!!
ricardo castro
From Chile
|
|
|
|
|
As originally conceived and implemented, the control displays a Static or snapshot view of Folders. RefreshTree is the only effective way of refreshing the view in the published version.
I have a long pending update that changes this in significant ways, but I have not found time to write the article and to fully reveiw the code. One of the things my pending update version lacks is a public method to refresh a single node via code in the using form. What it does have is the ability to refresh a single node each time it is selected or expanded by the user. Hopefully, I will get the new version along with a revised article posted in a few weeks.
|
|
|
|
|
Thanks for the quick answer.
I be waiting the new version.
|
|
|
|
|
I'm not sure what would cause this, but... When I site the control in a form, the tooltips for nodes that contain text that runs off the right border of the control are showing behind the form. I think it may have something to do with SetTreeViewImageList but not sure. Is it possible that HR = SendMessage(treeView.Handle, TVM_SETIMAGELIST, wParam, m_smImgList) could be altering the zorder within the base treeview? I'll play around with it and post here if I find a fix.
Has anyone else had this problem?
|
|
|
|
|
This problem has been discussed in the Forum under the thread:
Bug - Tooltip of nodes which arent shown completely
Which is currently on the 2nd screen of forum messages. The discussion is a bit murky so I will summarize it here. if you delete the line indicated below, and add the Visible_Changed routine shown below, the full name of the node will be displayed like a tooltip. However, the Icons will not show in the IDE. I have no idea what the underlying problem is. If you can find it, I will be very greatful. Otherwise, you get to choose between seeing the Icons in the IDE or having the tooltip display
From my development version of the control -- from Sub New of ExpTree
'Add any initialization after the InitializeComponent() call
'setting the imagelist here allows many good things to happen, but
' also one bad thing -- the "tooltip" like display of selectednode.text
' is made invisible. This remains a problem to be solved.
SystemImageListManager.SetTreeViewImageList(tv1, False)
One can remove the above line from Sub New, if, and only if, you have also added the following:
Private Sub tv1_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles tv1.VisibleChanged
If tv1.Visible Then
SystemImageListManager.SetTreeViewImageList(tv1, False)
If Not Root Is Nothing Then
Root.Expand()
If Not IsNothing(tv1.SelectedNode) Then
tv1.SelectedNode.Expand()
Else
tv1.SelectedNode = Me.Root
End If
End If
End If
End Sub
One aspect of the problem is that .Net is not aware that the TreeView has an active imagelist -- I basically cut it out of the action by assiging the Imagelist via the SendMessage call. This is also why the Visible_Changed handler is required.
|
|
|
|
|
Sorry Jim, guess I should have read further. Thanks for the info.
|
|
|
|
|
No problem. I encourage you to dig deeper and find the underlying cause. I am currently hung up over a different, but superficially similar problem within the IDE, so someone else is going to have to chase this one.
Good Luck,
Jim Parsells
|
|
|
|
|
Hi Jim,
I changed the SetTreeViewImageList to be in the VisibleChanged event and everything is working great in the IDE and the compiled <release> version... including icons. However, I made a significant change to your sample in that I don't have a treeview sited on a usercontrol. I have a class that inherits from Treeview. I wanted to be able to have your functionality but still use the control as a regular treeview. I use an event sink to capture and respond to events from the base treeview:
'In declarations
Private WithEvents EventSink As ExTreeView
'In Sub New
EventSink = Me
Private Sub EventSink_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles EventSink.VisibleChanged
If MyBase.Visible Then
SystemImageListManager.SetTreeViewImageList(Me, False)
If Not Root Is Nothing Then
Root.Expand()
If Not IsNothing(MyBase.SelectedNode) Then
MyBase.SelectedNode.Expand()
Else
MyBase.SelectedNode = Me.Root
End If
End If
End If
I'm not using a usercontrol at all. I simply declare a module-level variable (withevents, of course) and add it to my controls on Sub New of the form. I would imagine that one could also load the derived class into the usercontrol and the problem may be fixed there as well, but I havent tried that.
Let me know if you'd like additional info, and thanks very much for a great control.
BTW, another thing I'd like to look into is using, and responding to, the Shell's context menu in the treeview. I believe this can be done using IContextMenu. Have you ever investigated this functionality?
Thanks,
Jeff Beem
|
|
|
|
|
Hmmm, Very interesting. It is interesting in it's own right and also in terms of its implications for what I have been spending my time on, Drag&Drop.
I have to think this over, and will reply off-forum in a little while.
There is some overall commonality between Drag&Drop and IContextMenu, and, although I haven't thought much beyond that, it seems that a coordinated approach will be useful. The main issue is that my current implementation of Drag&Drop requires ExpTree to be a user control rather than an inherited one. However, it seems possible that this could be changed. I will be in touch.
Jim Parsells
|
|
|
|
|
Hi Jim,
I made a mistake. I guess I'm still used to some of the VB6 terminologies my peers and I used to use where "in the IDE" also meant "while running in debug mode". I was debugging, seeing the icons, and that's what I was talking about when I said I had icons "in the IDE". I just compiled my dll and loaded the class into a usercontrol, compiled that control, and then placed the control on a form and there were no icons "in the IDE". However, to me that's not such a big deal. If it works correctly at runtime (including tooltips") that's as much as one can really expect, IMHO.
Thanks for taking all my questions
-Jeff Beem
|
|
|
|
|
Jeff,
OK -- that's the choice you get to make. I just wish someone could figure out how to fix it. I do it one way, but this thread shows how to do it the other way.
I still will get back to you off-forum about IContext. Of course, you can use .Net's context menus with ExpTree, but if you wish to see the proper Shell context menu for a folder, you will have to use IContext and do some mildly tricky stuff (he says wryly) to get the desired effect. It probably is not as bad as the code I had to use to get the Shell IDataObject to drop on a Shell Folder's IDropTarget. That actually wasn't too bad, though the devil lives in the details. My problems with Drag&Drop have more to do with updating ExpTree to reflect the operation.
Jim Parsells
|
|
|
|
|
The component success to get the right icon for any file or folder and that's not trivial at all.
Though, the code is a mess. More documentary on the code itself and the main algorithm could be a bless.
|
|
|
|
|
Thanks for the feedback. A little more clarification of your comment would be nice though.
Jim Parsells
|
|
|
|
|
The whole code is not documented at all, it's a bunch of code line without explaining what are you doing and why?
For example, as far as I know when you have a PIDL you can get an icon with SHGetFileInfo without any LinkOverlays flags but you do check if the file is a link, system file etc.
I'm not saying it's not good and everything seem to work but I couldn't understood what you are trying to do.
I think that you should wrap some of the functionality in wrapper classes. (For example: FileDataPath that gets file path and handle files only and performing all the shells manipulations inside it).
I think that if you had seperated directories and files handling to different classes and try to make some sense in the code flow it could be perfect.
|
|
|
|
|
The article is the documentation. I assume that people would read & understand that, before going on to the code. I specifically did not devote much of the article to the CShItem class -- leaving that to a separate article "if there is enough interest shown". There hasn't been.
The article DOES explain -- in terms of SystemListManager -- why ShGetFileInfo is called the way it is called.
Dividing the CShItem class between File related and Directory related simply complicates the using code's task, and does not, by definition, give a good representation of System Folders, Folder Shortcuts, and other non-Filesystem entities --- exactly the problem with the .Net File and Directory classes.
Jim Parsells
|
|
|
|
|
Most of the shell calls lies in the CShItem.
Leaving it undocumented causes this main class to be uncovered on both - article and code.
Here is a typical code piece:
Private Function GetContents(ByVal flags As SHCONTF) As ArrayList<br />
.....<br />
<br />
If Not XPorAbove Then<br />
If CBool(attrFlag And SFGAO.FOLDER) Then 'Don't need it<br />
GoTo SKIPONE<br />
End If<br />
Else 'XP or above<br />
If CBool(attrFlag And SFGAO.FOLDER) AndAlso _<br />
Not CBool(attrFlag And SFGAO.STREAM) Then<br />
GoTo SKIPONE<br />
End If<br />
End If<br />
End If<br />
rVal.Add(New CShItem(m_Folder, item, Me))<br />
SKIPONE: Marshal.FreeCoTaskMem(item) 'if New kept it, it kept a copy<br />
item = IntPtr.Zero<br />
itemCnt = 0<br />
Application.DoEvents()<br />
HR = IEnum.GetNext(1, item, itemCnt)<br />
Loop<br />
Else<br />
If HR <> 1 Then GoTo HRError '1 means no more<br />
End If<br />
Else : GoTo HRError<br />
End If<br />
'Normal Exit<br />
NORMAL: If Not IsNothing(IEnum) Then<br />
Marshal.ReleaseComObject(IEnum)<br />
End If<br />
rVal.TrimToSize()<br />
Return rVal<br />
<br />
' Error Exit for all Com errors<br />
HRError: 'not ready disks will return the following error<br />
If HR = &HFFFFFFFF800704C7 Then<br />
GoTo NORMAL<br />
ElseIf HR = &HFFFFFFFF80070015 Then<br />
GoTo NORMAL<br />
'unavailable net resources will return these<br />
ElseIf HR = &HFFFFFFFF80040E96 Or HR = &HFFFFFFFF80040E19 Then<br />
GoTo NORMAL<br />
ElseIf HR = &HFFFFFFFF80004001 Then 'Certain "Not Implemented" features will return this<br />
GoTo NORMAL<br />
End If<br />
If Not IsNothing(IEnum) Then Marshal.ReleaseComObject(IEnum)<br />
#If Debug Then<br />
Marshal.ThrowExceptionForHR(HR)<br />
#End If<br />
Return New ArrayList() 'sometimes it is a non-fatal error,ignored<br />
End Function
GOTO, explicit values for HR are all what is mainly called "spaghetti code". (Function based with many GOTO clauses and without OO design).
Jim, you succeed where others have failed but you have to understand that this is a friendly critics.
Open source is all about sharing knowledge and the code in it's current condition doesn't do that.
|
|
|
|
|
Ok,now w're getting somewhere. You are expressing an interest in knowing more about the CShItem class -- you are the first to directly do so.
My thoughts on GOTO: I try to use GOTO only where it ADDs to clarity. The GOTO debate has long since been beaten to death, and my position is that a GOTO can add more clarity than a page or two of terminating End Ifs or (worse) close brackets "}". Some functions, and GetContents is one of them, are not expressable in a single screen of code. My typical approach to this is to place all error exits at the end of the function, immediately preceeded by the normal exit -- unless a Try-Catch block will do the job -- which it won't in this case.
The long list of explicit error testing, as frequently discussed in the forum, is there to allow programmers to investigate OTHER errors that may arise. In my current version of GetContents (not yet published) the entire section is replaced by code that just ignores any errors and returns an empty Arraylist on error. The change is simple.
NORMAL: If Not IsNothing(IEnum) Then
Marshal.ReleaseComObject(IEnum)
End If
rVal.TrimToSize()
Return rVal
' Error Exit for all Com errors
HRError: rVal = New ArrayList()
GoTo NORMAL
End Function
Note that I still use GOTO to get to HRError and to NORMAL - the exit points.
The code that starts "If Not XPorAbove Then"
was a late addition, also discussed in the Forum, to compensate for the fact that, in XP, Zip files are Folders.
For some additional clarity, see:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_programming/folder_info.asp
and look at the sample code. Of course that sample is a bit less complex since it starts from a fixed base whereas GetContents allows the caller to specify whether or not to return non-Folders only (all those GOTO SKIPONE statements) or to return all items in the Folder. Unlike the sample, I do take explicit action on Error conditions.
Jim Parsells
|
|
|
|
|
Hi,
your component is awesome. But I'm facing one problem:
when I call ExpandANode("\\computer\share")
it comes through domain (NetworkNeigb\\MSNetwork\\Domain)
then if it searches computers in domain it does'n match any computer
I found that it is difference in PIDL in one byte (8th byte of PIDL after domain - computer PIDL)
20,0,31,88,96,44,141,32,234,58,105,16,162,215,8,0,43,48,48,157,20,0,71,0,2,69,110,116,105,114,101,32,78,101,116,119,111,114,107,0,51,0,70,0,130,77,105,99,114,111,115,111,102,116,32,87,105,110,100,111,119,115,32,78,101,116,119,111,114,107,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,31,0,65,0,130,70,101,108,105,115,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,33,0,66,0,130,92,92,
98,
114,99,107,111,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,40,0,195,1,197,92,92,98,114,99,107,111,92,102,101,108,105,115,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,0,2,0,0,0, - \\computer\share
20,0,31,88,96,44,141,32,234,58,105,16,162,215,8,0,43,48,48,157,0,0, - My Network Places MATCH
20,0,31,88,96,44,141,32,234,58,105,16,162,215,8,0,43,48,48,157,20,0,71,0,2,69,110,116,105,114,101,32,78,101,116,119,111,114,107,0,0,0, - Entire Network MATCH
20,0,31,88,96,44,141,32,234,58,105,16,162,215,8,0,43,48,48,157,20,0,71,0,2,69,110,116,105,114,101,32,78,101,116,119,111,114,107,0,51,0,70,0,130,77,105,99,114,111,115,111,102,116,32,87,105,110,100,111,119,115,32,78,101,116,119,111,114,107,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,0,0, - Microsoft Windows Network MATCH
20,0,31,88,96,44,141,32,234,58,105,16,162,215,8,0,43,48,48,157,20,0,71,0,2,69,110,116,105,114,101,32,78,101,116,119,111,114,107,0,51,0,70,0,130,77,105,99,114,111,115,111,102,116,32,87,105,110,100,111,119,115,32,78,101,116,119,111,114,107,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,31,0,65,0,130,70,101,108,105,115,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,0,0, - domain MATCH
20,0,31,88,96,44,141,32,234,58,105,16,162,215,8,0,43,48,48,157,20,0,71,0,2,69,110,116,105,114,101,32,78,101,116,119,111,114,107,0,51,0,70,0,130,77,105,99,114,111,115,111,102,116,32,87,105,110,100,111,119,115,32,78,101,116,119,111,114,107,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,31,0,65,0,130,70,101,108,105,115,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,33,0,66,0,130,92,92,
66,
114,99,107,111,0,77,105,99,114,111,115,111,102,116,32,78,101,116,119,111,114,107,0,2,0,0,0, - computer - DON'T MATCH
I put the difference on extra line
Any help?
if (Day.IsMidnight){GrBo = null; }
|
|
|
|
|
I have seen this before, but only with XP and only with the Control Panel. What OS are you using? The code does assume that a PIDL representing the same object will have the same content. This seems to be a false assumption for some objects on some systems. I am not using the appropriate API calls to manipulate & otherwise examine PIDLs because doing so would limit the control to Win2K and above. At this point, I don't event know whether the API would fix the problem. I will now have to look at that. Since the problem seems to occur only on XP, and the APIs are limited to Win2K and above, there is some hope that the API will do the right thing. If so, I am left to doing some conditional code based on OS. Oh Well.
Jim Parsells
|
|
|
|
|
Win XP English SP2 also Win XP German SP2
if (Day.IsMidnight){GrBo = null; }
|
|
|
|
|
Hi,
Have you tried to make your control work on VB 2005 ?
I did. I had to modify some things because I had several warnings and errors.
Everything is almost Ok but the multithreaded part does not work properly. It says at excution time that a control is being acceded from a thread that did not created it.
As I do not know (not yet at least ) how to program threads, I don't know what to do.
An idea ?
Thanks,
Patrick
|
|
|
|
|
Patrick,
I have not tried the control with VB2005. The actual control does not use threading at all. The DEMO does. As I have stated many times, the Demo is so tailored to be a demo that it does no useful work.
The download Demo uses a separate thread to load the Icons for the ListView. The Article description of this does not, and the AfterNodeSelect code from the article shows the loading of the Icons in a non-threaded fashion. Therefore, you can modify the Demo using the code from the Article to avoid using Threads at all. Of course it runs a bit less responsivly without the threads.
Given that I do not have VS 2005, I cannot duplicate your error. I can only speculate that there might be a change in VB2005 from defaulting to a STA model to a MTA, with additional restrictions imposed because of that. There is not doubt that the Demo's separate Thread is accessing a control not created on that Thread. That is the entire purpose of the separate Thread.
I am interested in hearing more about this, should you, or anyone else, find out more.
Thanks,
Jim Parsells
|
|
|
|
|
Hi Author of Explorer Tree,
I have VB .Net Professionals and I am not able to run the demo project as is.
I am getting more than 5 errors at compile/build.
What could be doing wrong, should I be inlcuding any libraries or DLLs.
I am trying to understand your code to develop a tool to orgainze photos/music across drives.
Any and all help I can get to understand your code will be appreciated.
Thanks & Regards
Ajay Kalidindi
|
|
|
|
|