|
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
|
|
|
|
|
Ajay,
What errors? The demo project as supplied in the download should work as is with VS2002 and should automatically convert with no errors to VS2003.
It you are getting errors on your own project, then it is probable that you did not add the appropriate reference to the ExpTreeLib dll. Extract the demo project and observe the references. Model your references accordingly.
If none of that applies to your problem, then let me know the details of the errors you are experiencing. Also, what version of Windows are you using? What version of Internet Explorer?
Jim Parsells
|
|
|
|
|
Your control in fantastic. Thanks to share it.
I am a beginner in VB.net and I was wandering if it would be difficult to add a thumbnails view style to the ImageList ???
Thanks again
Patrick
|
|
|
|
|
Note: The article and the associated ExpTreeLibrary does not contain the ListView component, which is where Thumbnail View would be relevant. The ListView is part of the Demo and is very tailored to show the capabilites of the Library, as opposed to doing anything else.
The short answer to your question is: I don't know, but probably not so much difficult as tricky. SystemImageListManager deals with the small and large System image list and assumes that no other element of the application will be modifying either, since it assumes/requires that an Icon will have the same IconIndex in both lists.
Adding Thumbnails clearly hss the potential of directly or indirectly violating this requirement.
There is also only one ListViewItem.Index property. The Demo takes advantage of only having one Index to worry about.
It may be possible to build a .Net ImageList with Thumbnails without causing bad side effects for SystemImageListManager, but I have not tried this and really do not know what the implications are.
If it can be done, then you would need code to change the ListViewItem.Index property as you switch between ThumbnailView and any other view.
If your app will only show Thumbnail View, then you could dispense with using SystemImageListManager for the ListView -- however, I do not guarantee the SystemImageListManager, as used by the TreeView would survive the extra Image processing your would be doing. Try it and see.
Jim Parsells
|
|
|
|
|
Message Closed
modified 24-Dec-20 6:48am.
|
|
|
|
|
The currently available version of the CShItem class has a limited filter capability. An alternate signature version of CShItem.GetFiles accepts a filter string...
Dim xxx as New CShItem(someFileSystemPath)
dim filtList as ArrayList=xxx.GetFiles("*.wav")
will return only CShItems representing .wav files to filtList. Since the underlying code is actually:
Public Function GetFiles(ByVal Filter As String) As ArrayList
If m_IsFolder Then
Dim dummy As New ArrayList()
Dim fileentries() As String
fileentries = Directory.GetFiles(m_Path, Filter)
Dim vFile As String
For Each vFile In fileentries
dummy.Add(New CShItem(vFile))
Next
Return dummy
Else
Return New ArrayList()
End If
End Function
it is obvious that any and all limitations of Directory.GetFiles apply.
Since the Demo DOES NO USEFUL WORK, it is also obvious that it order to do anything useful, one must modify the Demo code as it relates to the ListView.
Applying a Filter to displayed files is really of no interest to the ExpTree
control since the control only deals with Shell FolderItems that are themselves Folders. ExpTree wouldn't know what to do with a file if is saw one. This will change in a version of ExpTree that handles Drag/Drop, but that is not relevant to this question.
If you wished to have an OpenFileDialog replacement that returned a Filtered list of FileNames, it would be easy enough to write one given the ExpTreeLib routines. Calum McLellan's Browser control at: http://www.codeproject.com/article.asp?tag=17995122998338489
Gets you most of the way, with room on the form to add the filter spec.
Calum's control has some very nice visual enhancements and features.
Jim Parsells
|
|
|
|
|
Hi,
The ListView in my article has an Extensions property which will only allow certain extensions - I haven't used the CShItem function described by Jim because I wanted to add a bit of flexibility to how the filter strings are written, it will accept all of the following: jpg .jpg *.jpg test.jpg (test.jpg will return ALL jpg's not just a file called test.jpg). The other reason I didn't use the CShItem function was to avoid multiple calls (one for each file type) I figured that just getting all the files and then filtering them afterwards would be quicker in most cases - Thinking about it now I could be very wrong here... I think there could probably be a few perfomance improvements made to the AddItem sub, any opinions would be welcome.
The Extensions property is a string array and can be set in the designer.
Cheers
Calum
|
|
|
|
|
This is the way Filters should be handled ... just as Calum has done in his control. Gettting all files and then filtering them is not only more efficient, but maintains the proper division of labor between the various components.
Jim Parsells
|
|
|
|
|
Hi
>>>I have just finished the filter for files and I also added two properties where you can choose if you want to show hiddenfolders and hiddenfiles.<<<
When did I say that? I must have been talking about the ListView...
I have added a boolean ShowHiddenFolders property to the ExpTree . This just does a simple check in the BeforeExpand Sub as follows:
<code>If D.Count > 0 Then
D.Sort() 'uses the class comparer
Dim item As CShItem
For Each item In D
If Not (item.IsHidden And Not m_showHiddenFolders) Then 'Added Code
Dim newNode As TreeNode = MakeNode(item)</code>
I agree that the best place for a file filter is on the host form (or ListView). I will look into a more efficient way than what I have used in my ListView...
Cheers
Calum
|
|
|
|
|
[Refers to a message I mis-directed ... since deleted ....JP]
Whoops ... my mistake. I was replying to someone else ... in a message not actually posted on the Forum. Sorrry for the mis-directed message.
Jim Parsells
|
|
|
|
|
I like this approach better than the one I have in my unpublished version. I will make the changes to mine.
Jim Parsells
|
|
|
|
|
Hi, first of all, excellent component! Thank you very much
I'm wondering about a piece of code I found in the CShItem's GetContents method. It might be by design or it might be some old code, but nevertheless. It all started with my application taking awfully long time to start (>30 secs). I narrowed it down to the first call of the CShItem's GetContents (this case, CShItem representing the Desktop). I found this piece of interesting code inside a loop:
Application.DoEvents()
This statement is taking roughly 29secs to complete. I'm not sure if this is by design (bug work-around etc) or just left as an excerise to the user. Anyway, I'd like to know the implications of removing it, if any
Best regards,
Chris
|
|
|
|
|
Chris,
One of the benefits of code sharing like this is that you get to play with the code yourself to see how it might be changed to improve it;) Go ahead & remove it and see what happens.
In my case (for example the demo), that statement improved responsiveness.
What I have found is that the fetching of Icons (which just getting the IconIndex will do) dominates performance. Depending on what you have on the desktop and on the overall power of your machine, time to start could be noticable.
In my normal development case, I have a very cluttered desktop and am using a 3 year old system with an AMD processor which was pretty good 3 years ago I do not experience a noticible delay. On the other hand, I have no elements on my desktop that would require any kind of network activity to access.
Many performance profilers, when faced with a DoEvents statement charge it with all the time spent processing in other threads -- those allowed to proceed by the DoEvents. The nature of the DoEvents is such that if you have a lot going on in other threads, the thread with the DoEvents will slow down -- it is yeilding control, temporarily, to the other threads.
I will be interested to hear what you find out.
Jim Parsells
|
|
|
|
|
I think I might have been a bit too quick there. There is a delay in Application.DoEvents for some reason when using Application.EnableVisualStyles . The work-around is to use a manifest file, but I think I'll just skip it.
Sorry for any inconvenience, and thanks once more for the component
/Chris
|
|
|
|
|
Thanks for the follow up.
One of the early efforts with ExpTree, in part, allowed me to avoid using a Manifest with the control. Of course, if the rest of the app needs one, you have to provide it. Adding one is no big deal, it's just that I wanted to minimize the number of files the control required.
I have done absolutely nothing with VisualStyles, so I have nothing useful to say on that topic.
Jim Parsells
|
|
|
|
|